Security Scanning in AI/ML CI/CD Pipelines
How to integrate security scanning into AI/ML CI/CD pipelines: dependency scanning, container image analysis, model file validation, secrets detection, and infrastructure-as-code checks.
AI/ML projects carry security risks that standard application security scanning does not cover: pickle deserialization attacks in model files, excessive permissions for training jobs, sensitive data in training datasets, and prompt injection vulnerabilities. A DevSecOps pipeline for AI extends standard security scanning with ML-specific checks.
Pipeline Security Stages
Integrate security checks at every stage rather than adding a single security gate at the end.
Pre-Commit: Local Checks
Install pre-commit hooks that catch issues before code reaches the repository:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaks
- repo: https://github.com/PyCQA/bandit
rev: 1.9.4
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]Bandit catches common Python security issues: use of eval(), insecure random number generation, and hardcoded passwords. Gitleaks detects API keys and credentials before they enter the commit history.
CI: Automated Scanning
Run these checks on every pull request:
Dependency Scanning - Scan requirements.txt, pyproject.toml, and lock files for known vulnerabilities. ML projects depend on packages with large native code surfaces (PyTorch, TensorFlow, numpy, scipy) where CVEs are common.
- name: Scan dependencies
uses: aquasecurity/trivy-action@v0.36.0 # pin to a full commit SHA in production
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'HIGH,CRITICAL'
exit-code: '1'Static Analysis - Semgrep with ML-specific rules catches unsafe deserialization, SQL injection in data pipelines, and insecure API configurations:
- name: Semgrep scan
run: |
pip install semgrep
semgrep scan --error \
--config p/python \
--config p/security-audit \
--config p/owasp-top-tenThe older returntocorp/semgrep-action wrapper is deprecated; Semgrep now recommends running the Semgrep CLI (or the semgrep/semgrep container image) directly in CI.
Model File Validation - Reject pickle files in favour of safer serialization formats. Scan model artifacts for known malicious patterns:
# In CI pipeline
def validate_model_format(path):
"""Reject pickle, accept safetensors or ONNX."""
if path.suffix in ('.pkl', '.pickle'):
raise SecurityError(
f"Pickle files are not allowed: {path}. "
"Use safetensors or ONNX format."
)Pin third-party actions to a release, and ideally to a full commit SHA, rather than @master. The scanners themselves are a supply-chain target: in March 2026 attackers compromised release tags of aquasecurity/trivy-action, and Aqua Security re-published clean releases under v-prefixed tags (for example v0.35.0). See GitHub Actions security
for pinning and least-privilege GITHUB_TOKEN settings.
Infrastructure-as-Code Scanning - Checkov or tfsec validates Terraform and Kubernetes manifests:
- name: Checkov IaC scan
uses: bridgecrewio/checkov-action@v12 # pin to a full commit SHA in production
with:
directory: infrastructure/
framework: terraform,kubernetesContainer Image Scanning
AI inference containers often use large base images with CUDA drivers, increasing the attack surface. Scan images after build:
- name: Build image
run: docker build -t inference-service:${{ github.sha }} .
- name: Scan image
uses: aquasecurity/trivy-action@v0.36.0 # pin to a full commit SHA in production
with:
image-ref: 'inference-service:${{ github.sha }}'
severity: 'HIGH,CRITICAL'
exit-code: '1'Reduce the attack surface by using minimal base images. Use nvidia/cuda:12.x-runtime-ubuntu22.04 instead of the full development image. Multi-stage builds keep build tools out of the final image.
Secrets Management
AI projects handle numerous credentials: model provider API keys, database connections for feature stores, cloud storage credentials for training data. Never store them in code or environment files.
- Use AWS Secrets Manager or HashiCorp Vault for runtime secrets
- Use GitHub Actions secrets or OIDC federation for CI/CD credentials
- Rotate API keys for model providers regularly
- Audit secret access logs for anomalous patterns
AI-Specific Security Concerns
Training Data Leakage - Models can memorise and regurgitate training data. Scan training datasets for PII before training. Use differential privacy techniques for sensitive data. Document data provenance in the model card.
Prompt Injection - LLM-based services are vulnerable to prompt injection. Include prompt injection test cases in your CI evaluation suite. Test with adversarial inputs that attempt to override system instructions.
Model Supply Chain - Models downloaded from Hugging Face or other hubs can contain malicious code. Verify model checksums, prefer safetensors format, and scan model files before loading.
Excessive Permissions - Training jobs often run with overly broad IAM roles. Apply least-privilege: the training job needs read access to the training bucket and write access to the artifact bucket. It does not need access to production databases.
Balancing Security and Velocity
Security scanning adds pipeline time. Manage this by running fast checks (linting, secrets detection) on every commit and slower checks (full image scan, DAST) on merge to main. Cache scan results for unchanged dependencies. Set severity thresholds: fail on critical and high, warn on medium, ignore low.
The goal is not zero vulnerabilities. It is continuous visibility and rapid remediation of the vulnerabilities that matter.
Sources
- Aqua Security, trivy-action release v0.35.0 (re-published after the March 2026 supply-chain attack, 20 March 2026) and v0.36.0 (22 April 2026): https://github.com/aquasecurity/trivy-action/releases
- Semgrep, semgrep-action README (deprecation notice): https://github.com/returntocorp/semgrep-action
- Semgrep, “Sample CI configurations”: https://semgrep.dev/docs/semgrep-ci/sample-ci-configs
- Gitleaks releases (v8.30.1): https://github.com/gitleaks/gitleaks/releases
- Bandit releases (1.9.4): https://github.com/PyCQA/bandit/releases