Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Defender AI Model Security Lab

This is a standalone security lab. There is currently no published companion blog post, so it is intentionally omitted from the website's Labs catalog until a real companion article exists. Do not describe this repository as a companion lab or link it to an unpublished article.

The lab deploys an Azure Machine Learning (AML) workspace, safely validates or updates the documented Defender base plans with reversible lifecycle tracking, and deploys three disabled-by-default Microsoft Sentinel activity-audit rules plus a workbook. By default it builds and registers only a clean model. Deliberately unsafe demonstration artifacts require a separate, exact opt-in.

What is included

Artifact Default deploy Purpose Execution risk
clean_iris_rf.pkl Yes Negative-control sklearn model Normal pickle trust rules still apply
malicious_reduce.pkl No Demonstrates pickle REDUCE code execution Unsafe if deserialized; fixed local sentinel only
secret_exposed_model.pkl No Demonstrates fake credentials serialized with a model No intentional code execution
unsafe_torchscript.pt Never automatic Optional PyTorch pickle-opcode sample Unsafe if loaded; fixed local sentinel only

Microsoft controls supported model formats, scan timing, licensing, and feature availability. Verify the current behavior in your tenant and the linked Microsoft documentation rather than treating the examples here as a service-level guarantee.

Repository layout

.
├── .github/workflows/model-scan.yml  # Active, SHA-pinned CI workflow
├── ci/github-actions-model-scan.yml  # Identical copy for reuse
├── infra/
│   ├── main.bicep                    # AML workspace and dependencies
│   ├── sentinel-rules.bicep          # Provenance-marked rules and workbook
│   └── workbook.json
├── payloads/
│   ├── build_utils.py                # Atomic output and unsafe-build guard
│   ├── build_clean_model.py
│   ├── build_malicious_reduce.py
│   ├── build_secret_exposed.py
│   ├── build_unsafe_torchscript.py   # Optional; Torch is not installed by deploy
│   └── requirements.txt              # Exact Python dependency versions
├── scripts/
│   ├── deploy-lab.sh
│   ├── cleanup.sh
│   ├── install-defender-cli.sh       # HTTPS + mandatory SHA-256 verification
│   └── lab_state.py                  # Ownership and rollback manifest helper
└── tests/

Safety and cost boundary

Microsoft's public onboarding documentation exposes the AI model security component as a portal setting, while the public Microsoft.Security/pricings@2024-01-01 schema does not document an API extension for that component. This lab therefore does not send a guessed or reverse-engineered component value. Enable Defender for Cloud → Environment settings → AI services → Settings → AI model security first, then attest that the portal step is complete:

export CONFIRM_PORTAL_AI_MODEL_SECURITY=ENABLED-IN-DEFENDER-PORTAL

The deploy can still change the documented shared subscription-level CloudPosture and AI base pricing tiers if they are not already Standard. Before the first write it captures the mutable prior properties in .defender-ai-model-security-state.json, preserves subPlan, enforce, and every existing extension, and requires this separate acknowledgement:

export CONFIRM_SUBSCRIPTION_SCOPE=ENABLE-DEFENDER-CSPM-AND-AI-PLANS

These plans may incur Azure charges. The script does not silently select the active subscription, register resource providers, ignore plan failures, guess an undocumented component API, or replace unrelated extensions.

The two code-execution payload builders refuse to run unless this separate acknowledgement is present:

export CONFIRM_UNSAFE_MODEL_ARTIFACTS=BUILD-PICKLE-RCE-DEMO

Never unpickle or load those artifacts. Their reducers contain a fixed command that can only write a named sentinel under /tmp, with no network or destructive operation, but they remain executable untrusted data.

Prerequisites

  • An Azure subscription where you can deploy resource-group resources and manage Defender pricing.
  • Azure CLI with the ml extension already reviewed and installed.
  • Python 3.11+ with venv support.
  • A Log Analytics workspace already onboarded to Microsoft Sentinel.
  • These resource providers already registered: Microsoft.Insights, Microsoft.KeyVault, Microsoft.MachineLearningServices, Microsoft.OperationalInsights, Microsoft.Security, Microsoft.SecurityInsights, and Microsoft.Storage.
  • Defender CSPM, Defender for AI Services, and the portal-only AI model security component enabled for the target subscription.
  • Azure Activity data available in the Sentinel workspace for the AML audit rules and workbook. Connector configuration is tenant-specific and is not changed by this lab.

Deploy

Select the subscription yourself and pass the same ID explicitly:

az login
az account set --subscription '<subscription-id>'

export SUBSCRIPTION_ID='<subscription-id>'
export SENTINEL_WS_ID='/subscriptions/<subscription-id>/resourceGroups/<sentinel-rg>/providers/Microsoft.OperationalInsights/workspaces/<workspace>'
export CONFIRM_PORTAL_AI_MODEL_SECURITY=ENABLED-IN-DEFENDER-PORTAL
# Only required if the script reports that the documented base plans must change:
export CONFIRM_SUBSCRIPTION_SCOPE=ENABLE-DEFENDER-CSPM-AND-AI-PLANS

./scripts/deploy-lab.sh

The portal-component attestation is always required because there is no documented API readback in this repository. If both documented Defender base plans already match the required state, the subscription-scope confirmation is not needed and no pricing write occurs. A rerun must use the same subscription, Sentinel workspace, resource-group name, and lifecycle manifest. Target drift and pre-existing unowned resources fail closed.

The script performs these operations:

  1. Validates the explicit subscription, portal-component attestation, Sentinel workspace, provider registrations, and AML CLI extension.
  2. Captures the prior Defender pricing state before any mutation.
  3. Preflights deterministic Sentinel resource IDs and refuses provenance collisions.
  4. Changes only documented base-plan properties when required and records ownership before each write.
  5. Creates a provenance-tagged lab resource group and deploys the AML infrastructure.
  6. Deploys or updates only lab-owned, disabled-by-default Sentinel AzureActivity audit resources.
  7. Builds and registers the clean model.

Opt in to the demonstration findings

To additionally build and register the pickle code-execution and fake-secret samples:

export BUILD_UNSAFE_PAYLOADS=true
export CONFIRM_UNSAFE_MODEL_ARTIFACTS=BUILD-PICKLE-RCE-DEMO
./scripts/deploy-lab.sh

The optional PyTorch checkpoint is never part of the deploy. After independently reviewing and installing a pinned CPU-only Torch build in an isolated environment, run its builder with the same unsafe-artifact confirmation. Do not load the output.

Sentinel activity-audit content and its limits

The official AI model-security documentation surfaces scan results as Defender security findings/recommendations; it does not document an Ai.AIModelScan* security-alert family. Accordingly, this repository does not pretend those findings exist in Sentinel's SecurityAlert table.

The deployment creates these exact, provenance-marked Azure Activity audit resources when their deterministic IDs are unoccupied. Rules are disabled by default to avoid turning expected lab actions into incidents:

Rule Signal actually proven
AML model registration or update observed A successful AML model write appears in AzureActivity
Repeated AML model or deployment writes by same caller Two or more relevant write events share the same provider-supplied Caller value in seven days
AML endpoint deployment write requires scan verification A successful AML online or batch endpoint-deployment write appears in AzureActivity

These signals do not contain model contents or scan verdicts. A repeated Caller value is an audit lead, not proof of compromise. The deployment-review rule does not claim a scan was missing or incomplete. Review model findings separately in Defender for Cloud or via a trusted Defender CLI SARIF result. The workbook repeats these boundaries.

Defender CLI and GitHub Actions

The active workflow is .github/workflows/model-scan.yml; ci/github-actions-model-scan.yml is an identical reusable copy, not a nonexistent symlink. It scans model files under models/ only. Intentionally unsafe lab payloads are never generated or included in that CI search path.

Configure these GitHub settings:

  • OIDC secrets: AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_SUBSCRIPTION_ID.
  • Repository variable DEFENDER_CLI_SHA256: the reviewed 64-character SHA-256 for the exact Linux Defender CLI binary.
  • Optional repository variable DEFENDER_CLI_URL: an alternate reviewed HTTPS URL. If omitted, the official short URL in the installer is used, but the checksum remains mandatory.

All workflow actions are pinned to full commit SHAs. The local installer downloads over HTTPS, rejects a checksum mismatch, and never pipes remote content into a shell:

export DEFENDER_CLI_SHA256='<reviewed-64-character-sha256>'
export DEFENDER_CLI_INSTALL_DIR="$PWD/.local/bin"
bash ./scripts/install-defender-cli.sh

Cleanup and rollback

Use the same exact target values as deployment:

export SUBSCRIPTION_ID='<subscription-id>'
export SENTINEL_WS_ID='/subscriptions/<subscription-id>/resourceGroups/<sentinel-rg>/providers/Microsoft.OperationalInsights/workspaces/<workspace>'
./scripts/cleanup.sh

Cleanup validates the manifest, restores only Defender plan state changed by this run, deletes only exact Sentinel resources recorded as lab-owned, and deletes the lab resource group only when its ID and provenance tag match. It never enumerates or purges Key Vaults by prefix.

Azure retains the exact soft-deleted Key Vault for recovery by default. Permanent purge is optional and irreversible; the confirmation includes the manifest-recorded name:

export CONFIRM_EXACT_KEY_VAULT_PURGE='PURGE-<exact-key-vault-name-from-cleanup-output>'
./scripts/cleanup.sh

The lifecycle manifest is intentionally retained as an audit record after cleanup. Archive or deliberately remove it only when starting a genuinely new lifecycle.

References

About

Lab: detect malicious AI models in Azure ML with Microsoft Defender for Cloud. Pickle RCE, exposed secrets, and unsafe opcodes caught before production. Includes Bicep, Sentinel analytics, workbook, and GitHub Actions SARIF gate.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages