14 / 70 · 07 Security Testing for AI Apps · Supply Chain Vulnerabilities, Overreliance, and Model Theft← prev⊞ allnext →☰ Read as one page
3.1LLM05: Supply Chain Vulnerabilities
The ML supply chain introduces risks absent from traditional software. Compromised model weights, poisoned fine-tuning data, malicious packages in the ML pipeline, and unverified model provenance can all undermine the security of your AI application.
ML Supply Chain Attack Surface
[Pre-trained Model] <-- Threat: Backdoored weights from untrusted source
|
v
[Fine-tuning Data] <-- Threat: Poisoned data injecting biases or backdoors
|
v
[ML Libraries] <-- Threat: Compromised PyTorch, TensorFlow, LangChain packages
|
v
[Model Registry] <-- Threat: Tampered model files, missing integrity checks
|
v
[Inference Runtime] <-- Threat: Vulnerable serving infrastructure
|
v
[Production API] <-- Threat: Exposed endpoints, missing authentication
Testing Supply Chain Security
# test_supply_chain.py
import hashlib
import subprocess
def test_model_weights_checksum():
"""Verify model weights match their expected checksum (provenance check)."""
expected_checksums = {
"model-v3.2.bin": "sha256:a1b2c3d4e5f6...",
"embeddings-v1.0.bin": "sha256:f6e5d4c3b2a1...",
}
for filename, expected_hash in expected_checksums.items():
with open(f"/models/{filename}", "rb") as f:
actual_hash = f"sha256:{hashlib.sha256(f.read()).hexdigest()}"
assert actual_hash == expected_hash, (
f"Model file {filename} has unexpected checksum. "
f"Expected {expected_hash}, got {actual_hash}. "
"The model may have been tampered with."
)
def test_ml_dependencies_no_critical_cves():
"""Verify no critical CVEs in ML library dependencies."""
result = subprocess.run(
["pip", "audit", "--format", "json"],
capture_output=True, text=True
)
import json
findings = json.loads(result.stdout)
critical = [f for f in findings if f["severity"] == "critical"]
assert len(critical) == 0, (
f"Critical CVEs found in ML dependencies: "
f"{[f['package'] + '@' + f['version'] for f in critical]}"
)
def test_model_source_is_trusted():
"""Verify models are loaded from trusted registries only."""
allowed_sources = [
"huggingface.co/our-org/",
"s3://our-model-bucket/",
"registry.internal/models/",
]
model_config = load_model_config()
for model in model_config["models"]:
source = model["source"]
assert any(source.startswith(s) for s in allowed_sources), (
f"Model '{model['name']}' loaded from untrusted source: {source}"
)