Skip to main content

Overview

This lab uses Microsoft’s GigaWiper research as a case study for the July 2026 preview of Defender XDR custom detection rules as code. It includes five rule definitions, a disabled deployment canary, GitHub validation, hunting queries, synthetic KQL fixtures, a bounded Windows telemetry generator, and a manual Graph-only fallback after the native preview path returned the result observed July 11–12, 2026.

Blog post: GigaWiper Detection as Code: Testing the Sentinel Repositories Preview

Companion repository: j-dahl7/gigawiper-detection-as-code

Safety boundary

The lab does not download malware, wipe disks, encrypt files, delete boot files, disable recovery, or clear operational Windows logs. Boot/recovery behavior is validated only with synthetic KQL rows.

What the pack defines

IDDetectionDesired stateEvidence path
nls-gw-000-canaryDeployment canaryDisabledExact-ID API read-back
nls-gw-001-onedrive-persistenceOneDrive-lookalike task and registry persistenceEnabledCurrent query re-matched live telemetry; the separate scheduled portal alert used the validation revision
nls-gw-002-recovery-boot-tamperingRecovery and boot tamperingEnabledSynthetic only
nls-gw-003-event-log-destructionWindows event-log clearingEnabledObserved benign custom-log telemetry plus a separate portal-native scheduled alert
nls-gw-004-minio-transfer-stagingUnusual MinIO client stagingEnabledFilename-only telemetry plus a separate portal-native NRT alert
nls-gw-005-candy-rename-burst.candy rename burstEnabledCurrent optimized query matched live telemetry; no saved portal rule or alert

The six retained exact IDs were read back in the validation revision’s desired state through the bounded Graph fallback. The disabled canary and five enabled behavior rules had zero current automatedActions and zero deprecated responseActions. Alert evidence below belongs only to three separately created portal-native validation rules.

Revision boundary: the current NLS-GW-001 post-correlation deduplication and optimized NLS-GW-005 time-window join were independently re-run read-only against retained live telemetry. Neither current revision was applied to the six retained Graph objects or the portal-native validation rules, and no new alert is attributed to either revision.

Quick start

Plan for 90–150 minutes of hands-on work. If this is the first subscription in the tenant to activate Defender for Endpoint through Defender for Cloud, allow up to 12 hours for service activation, followed by possible telemetry-ingestion delay. Do not generate validation telemetry until the machine API reports the endpoint Onboarded and Active and Advanced Hunting returns DeviceInfo.

git clone https://github.com/j-dahl7/gigawiper-detection-as-code.git
cd gigawiper-detection-as-code

./scripts/Test-Lab.ps1

The validation workflow compiles all six templates and checks the stable-ID, single-tactic, query-column, fixture, endpoint, fallback, and safety contracts.

In a dedicated lab tenant, you can connect the repository through Microsoft Sentinel > Content management > Repositories and select Custom Detection Rules to examine the native preview path. In the July 11–12 validation window, that generated path failed all six corrected templates with outer InvalidTemplateDeployment and inner ProviderError: Encountered internal server error. Because the root cause remains unconfirmed, broader role assignments are not a validated workaround.

If you intentionally use the temporary fallback, first follow docs/GRAPH-FALLBACK.md to create your own dedicated Entra application, GitHub OIDC credential, and environment. The identity must have only the Microsoft Graph application permission CustomDetection.ReadWrite.All and no Azure RBAC assignment. Then manually run Deploy custom detections - preview fallback from main, enter the exact confirmation DEPLOY_PREVIEW_FALLBACK, deploy the disabled canary first, and select All only after its exact-ID read-back succeeds. Do not run the fallback concurrently with a working native synchronization path.

Run safe telemetry only from an elevated session on a disposable MDE endpoint:

./scripts/Invoke-SafeGigaWiperTelemetry.ps1

Cleanup

./scripts/Invoke-SafeGigaWiperTelemetry.ps1 -CleanupOnly

Then complete the control-plane cleanup:

  • Remove the Sentinel Repository connection, then verify that its connection-created managed identity and Microsoft Sentinel Contributor, Logic App Contributor, CustomDetection.ReadWrite.All, and branch-scoped GitHub OIDC grants are retired. Deselecting Custom Detection Rules only stops that content type and is not identity cleanup.
  • Delete only the six exact nls-gw-* custom detection IDs through Defender XDR or a separately authorized Graph operation. The fallback has no delete or prune mode.
  • Separately delete portal rules NLS-GW-LIVE-001, NLS-GW-LIVE-003, and NLS-GW-LIVE-004; there is no LIVE-005 object.
  • Delete the dedicated fallback app registration and GitHub environment variables after rule cleanup.
  • Delete the remaining credential-less nls-gigawiper-validation-20260711 diagnostic app registration and its tenant-wide Graph grants.
  • Delete only the dedicated disposable Azure resource group used for endpoint validation.

Current validation status

Live tenant validation ran July 11–12, 2026; repository hardening and CI were revalidated July 13:

  • The Bicep pack, endpoint template, five positive plus five negative exact-query fixture contracts, fallback controls, and safety tests pass locally. The separate read-only synthetic runner passed all ten rows through Advanced Hunting.
  • The native Repository connection targets main, uses the CustomDetection content type, and generated its expected OIDC workflow. Its identity held the documented Graph permission and could read a rule by exact ID.
  • The connection-generated native workflow and helper are retained outside .github/workflows as non-reusable evidence artifacts. They cannot run from the public repository. A native retest requires a new Repository connection, review of its freshly generated files, and a deliberate ownership transfer away from the Graph fallback.
  • Native synchronization returned outer InvalidTemplateDeployment and inner ProviderError for all six corrected templates. That non-specific native-path response is distinct from the earlier Graph InvalidInput - Only one tactic is currently supported contract error, which was corrected and added to CI.
  • Manual Graph-only GitHub OIDC fallback run 29180593038 succeeded. All six validation-revision IDs returned HTTP 200 and passed semantic read-back: five rules enabled, the canary disabled, and zero response actions on every rule. The later current NLS-GW-001 and NLS-GW-005 revisions were not applied to those retained objects.
  • The fallback identity has only CustomDetection.ReadWrite.All, no stored secret, and zero Azure RBAC assignments. The workflow operates only on the exact six IDs, uses GET plus POST or PATCH, and has no delete or prune path.
  • The disposable endpoint has default inbound deny and no custom inbound NSG rules. The Defender machine API reports it Onboarded and Active, and Advanced Hunting receives DeviceInfo.
  • The four bounded telemetry jobs exited successfully. The exact checked-in KQL produced live benign matches for NLS-GW-001, NLS-GW-003, NLS-GW-004, and NLS-GW-005. Seven inert .candy rename rows satisfied the burst query after an ingestion delay. NLS-GW-002 remains synthetic-only by design.
  • Three separately created portal-native rulesβ€”NLS-GW-LIVE-001, NLS-GW-LIVE-003, and NLS-GW-LIVE-004β€”generated three Custom detection / Microsoft Defender for Endpoint alerts on nls-gw-lab. Incident 628 is High with Active alerts 3/3, and all three alert pages record that no response actions were taken.
  • LIVE-001 and LIVE-003 alerted during their initial scheduled evaluation over prior benign telemetry. The LIVE-004 NRT alert incorporated a post-rule safe marker as its last activity; the evidence does not establish that marker as the alert’s sole cause.
  • NLS-GW-005 matched live telemetry, but repeated portal wizards stopped at Supported entities could not be loaded; no 005 portal rule or alert exists or is claimed. NLS-GW-002 remains synthetic-only.
  • A separate built-in Defender alert, System executable renamed and launched, remains outside the three custom-alert claim.

The companion article’s evidence set includes the native-failure capture, Graph fallback and scheduler output, Advanced Hunting results, the LIVE-004 no-actions page, a historical one-alert incident view, and a tightly cropped final incident 628 Alerts tab. The final capture shows the High, Active incident with exactly LIVE-004, LIVE-003, and LIVE-001 on nls-gw-lab. The crop removes the global portal header and account or tenant identifiers while preserving the incident and alert rows. Before the LIVE rules were created, an exact NLS-GW filter returned zero rows despite successful Graph read-back. A follow-up filter now returns exactly the three LIVE rules and still none of the six Graph-fallback objects. Their portal visibility remains a separate open validation item; the cause is unconfirmed, and no alert attribution is assigned to those objects. Native Repository synchronization remains recorded in its observed Failed state.