Supply-Chain Security for Agent Sandboxes

Section 49.4

"Your agent is only as secure as the least audited dependency in its container image."

GuardGuard, Supply-Chain-Aware AI Agent
Big Picture

Agent sandboxes are only as secure as the software running inside them. Section 49.2 covered how to isolate agent execution with containers and microVMs. This section addresses a complementary threat: the software supply chain within those sandboxes. When an agent installs packages, pulls base images, or executes code from external sources, it inherits every vulnerability and backdoor in those dependencies. Supply-chain security tools (SBOM generation, vulnerability scanning, image signing, provenance attestation) provide the verification layer that ensures sandbox contents are trustworthy, not just isolated.

Hardening an agent sandbox with SBOM, scan, sign, and attest
Figure 49.4.1: An agent's dynamic dependency set turns every pip install into an attack surface. The hardening chain is: Syft generates a CycloneDX SBOM, Trivy or Grype scans for CVEs, cosign signs the resulting image with Sigstore keyless identities, and a runtime admission policy rejects anything missing a valid signature, scan, or provenance attestation. This is the same pattern that blocked dependency-confusion exploits like Alex Birsan's 2021 bug bounty run.

Prerequisites

This section builds on the sandboxed execution environments from Section 49.2 and the agent safety foundations in Section 49.1. Familiarity with Docker, container images, and basic CI/CD pipeline concepts is assumed. Understanding of tool use patterns from Chapter 26 provides helpful context for why agents need to install and execute arbitrary code.

49.4.1 Why Agent Sandboxes Need Supply-Chain Hardening

Fun Fact

The dependency confusion attack vector was disclosed by Alex Birsan in 2021, who collected over $130,000 in bug bounties from Apple, Microsoft, Tesla, Yelp, PayPal, Uber, Shopify, and 27 other companies in a single research run. He published private internal package names by reading the JavaScript files in those companies' public websites; the package-managers cheerfully installed his proof-of-concept payloads instead of the real internal libraries.

Agentic AI systems differ from traditional software in a critical way: the agent decides at runtime which packages to install, which APIs to call, and which code to execute. A coding agent asked to "build a data visualization" might install matplotlib, pandas, seaborn, and a dozen transitive dependencies. A research agent might pull a specialized NLP library the developer never anticipated. Each installed package is an attack surface: it might contain a known vulnerability (CVE), a malicious post-install script, or a dependency confusion payload that hijacks a private package name.

Traditional applications lock their dependencies at build time, audit them once, and deploy a fixed artifact. Agent sandboxes, by contrast, assemble their dependency set dynamically. This means the security posture of an agent sandbox can change between one task and the next. A sandbox that was safe for yesterday's task might be compromised by today's task if the agent installs a package with a newly disclosed vulnerability. Supply-chain hardening provides the tooling to detect, prevent, and recover from these risks.

The threat is not theoretical. In 2024, the Trivy project itself experienced a CI compromise where a malicious pull request attempted to inject code into the build pipeline. Dependency confusion attacks (where an attacker publishes a malicious package to PyPI or npm using the same name as a private internal package) have targeted organizations including Apple, Microsoft, and Tesla. For agent systems that install packages on behalf of users, these attacks are especially dangerous because the agent, not the developer, is making the installation decision.

Key Insight

The fundamental tension in agent sandbox security is between flexibility and control. Agents need to install packages to accomplish tasks. But every installed package is a potential vector for supply-chain attacks. The solution is not to prohibit package installation (that would cripple the agent) but to verify, scan, and attest every component that enters the sandbox. Think of supply-chain security as the "immigration checkpoint" for your sandbox: everything that enters gets inspected, documented, and verified before it is allowed to execute.

49.4.2 SBOM Generation with Syft

A Software Bill of Materials (SBOM) is a complete inventory of every software component in a container image or filesystem. It lists each package, its version, its source, and its license. SBOMs serve two purposes in agent security: (1) they provide the input for vulnerability scanners (you cannot scan what you have not inventoried), and (2) they create an audit trail of exactly what software was present in the sandbox when a task executed.

Syft (from Anchore) is the standard open-source tool for generating SBOMs. It supports multiple output formats (SPDX, CycloneDX, Syft JSON) and can scan container images, directories, and archives. Syft detects packages from multiple ecosystems: APK (Alpine), APT (Debian/Ubuntu), RPM (RHEL/Fedora), pip (Python), npm (Node.js), Go modules, Rust crates, and Java JARs.

#!/usr/bin/env bash
# Generate an SBOM for the agent-runner container image
# Install Syft (one-time setup)
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# Scan the container image and produce a CycloneDX JSON SBOM
syft packages registry.example.com/agent-runner:latest \
-o cyclonedx-json \
> sbom-agent-runner.cdx.json
# Inspect the SBOM: count packages by ecosystem
echo "Package counts by type:"
cat sbom-agent-runner.cdx.json | \
python3 -c "
import json, sys, collections
bom = json.load(sys.stdin)
types = collections.Counter(
    c.get('purl', '').split('/')[0].replace('pkg:', '')
    for c in bom.get('components', [])
    if c.get('purl')
    )
for t, count in types.most_common():
    print(f' {t}: {count}')
    "
Output: Package counts by type: pypi: 142 deb: 89 golang: 23 npm: 12 binary: 4
Code Fragment 49.4.1a: Uses Syft to generate a CycloneDX SBOM from a container image, then pipes the JSON through Python to count packages per ecosystem (pypi, deb, golang, npm). Producing the inventory before a vulnerability scan is the prerequisite step: you cannot scan what you have not enumerated.

For agent sandboxes with dynamic dependencies, generate the SBOM after the agent installs its packages but before the agent executes the task code. This captures the complete dependency set for that specific task. Store the SBOM alongside the task execution log so you can retrospectively audit which packages were present when a particular task ran.

49.4.3 Vulnerability Scanning with Trivy

Trivy (from Aqua Security) is a comprehensive vulnerability scanner for containers, filesystems, git repositories, and Kubernetes clusters. Given an SBOM or a container image, Trivy matches each package against vulnerability databases (NVD, GitHub Advisory Database, OS-specific advisories) and reports known CVEs with severity ratings (CRITICAL, HIGH, MEDIUM, LOW). Trivy also detects misconfigurations (e.g., running as root, exposed secrets) and license violations.

#!/usr/bin/env bash
# Scan the agent-runner image for vulnerabilities
# Scan container image directly
trivy image registry.example.com/agent-runner:latest \
--severity CRITICAL,HIGH \
--format json \
--output trivy-report.json
# Alternatively, scan from an existing SBOM
trivy sbom sbom-agent-runner.cdx.json \
--severity CRITICAL,HIGH \
--format table
# Scan a filesystem (useful for scanning the sandbox after package install)
trivy fs /sandbox/workspace \
--scanners vuln,secret,misconfig \
--severity CRITICAL,HIGH
# Exit code 1 if vulnerabilities found (useful for CI gates)
trivy image registry.example.com/agent-runner:latest \
--exit-code 1 \
--severity CRITICAL
Code Fragment 49.4.2: Trivy scanning an agent-runner container image and filesystem for vulnerabilities. The exit-code flag enables CI gate enforcement: the build fails if critical vulnerabilities are found. The fs scanner can be run inside the sandbox after the agent installs packages.

For agent sandboxes, integrate Trivy scanning at two points. First, scan the base image during CI to ensure it ships without known vulnerabilities. Second, scan the sandbox filesystem after the agent installs packages but before task execution. If the post-install scan finds a critical vulnerability, the sandbox runtime can block execution and return an error to the user, explaining that a required package has a known security issue.

import subprocess
import json
def scan_sandbox(workspace_path: str) -> dict:
    """Scan the agent sandbox workspace for vulnerabilities after package install."""
    result = subprocess.run(
        [
        "trivy", "fs", workspace_path,
        "--scanners", "vuln,secret",
        "--severity", "CRITICAL,HIGH",
        "--format", "json",
        "--quiet",
        ],
        capture_output=True,
        text=True,
        )
    report = json.loads(result.stdout) if result.stdout else {"Results": []}
    # Aggregate findings
    critical = []
    high = []
    for target in report.get("Results", []):
        for vuln in target.get("Vulnerabilities", []):
            entry = {
                "id": vuln["VulnerabilityID"],
                "package": vuln["PkgName"],
                "installed": vuln["InstalledVersion"],
                "fixed": vuln.get("FixedVersion", "not yet"),
                "title": vuln.get("Title", ""),
                }
            if vuln["Severity"] == "CRITICAL":
                critical.append(entry)
            else:
                high.append(entry)
                return {
                    "safe": len(critical) == 0,
                    "critical_count": len(critical),
                    "high_count": len(high),
                    "critical": critical,
                    "high": high,
                    }
                # Usage in the sandbox runtime
                scan = scan_sandbox("/sandbox/workspace")
                if not scan["safe"]:
                    raise SecurityError(
                        f"Sandbox blocked: {scan['critical_count']} critical vulnerabilities found. "
                        f"First: {scan['critical'][0]['id']} in {scan['critical'][0]['package']}"
                        )
Code Fragment 49.4.3: Python wrapper for Trivy filesystem scanning, designed to run inside the agent sandbox after package installation. If critical vulnerabilities are found, task execution is blocked with a descriptive error message.

49.4.4 Image Signing and Verification with Cosign

Vulnerability scanning tells you whether a container image contains known vulnerabilities. Image signing tells you whether the image is the one you built, or whether it was tampered with in transit or at rest. Cosign (from the Sigstore project) provides keyless signing and verification of container images using short-lived certificates issued by Fulcio and recorded in the Rekor transparency log. "Keyless" means there is no long-lived signing key to manage; instead, Cosign uses OIDC identity (e.g., your CI system's workload identity) to obtain an ephemeral signing certificate.

#!/usr/bin/env bash
# Sign and verify the agent-runner container image with Cosign
# Sign the image (keyless mode, uses OIDC identity from CI)
cosign sign registry.example.com/agent-runner:latest
# Verify the signature, checking that it was signed by the expected identity
cosign verify registry.example.com/agent-runner:latest \
--certificate-identity "https://github.com/yourorg/agent-runner/.github/workflows/build.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
# Attach the SBOM as an attestation to the image
cosign attest \
--predicate sbom-agent-runner.cdx.json \
--type cyclonedx \
registry.example.com/agent-runner:latest
# Verify the SBOM attestation
cosign verify-attestation \
--type cyclonedx \
--certificate-identity "https://github.com/yourorg/agent-runner/.github/workflows/build.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
registry.example.com/agent-runner:latest
Code Fragment 49.4.4: Cosign keyless signing, verification, and SBOM attestation for an agent-runner container image. The certificate-identity flag ensures only images signed by the expected CI workflow are accepted. The SBOM attestation binds the inventory to the specific image digest.

In the agent sandbox deployment pipeline, configure the container runtime (Kubernetes admission controller, Docker content trust, or a custom policy engine) to reject any image that lacks a valid Cosign signature. This prevents deployment of unsigned or tampered images, even if an attacker gains write access to the container registry.

Key Insight

Image signing and SBOM attestation together answer two distinct questions. The signature answers "who built this image, and has it been modified since?" The SBOM attestation answers "what is inside this image?" By requiring both, you establish a chain of trust from the CI build to the production sandbox. An attacker who replaces the image is caught by the signature check. An attacker who injects a vulnerable dependency is caught by the SBOM scan. Neither control alone is sufficient; together they provide defense in depth.

49.4.5 The SLSA Framework: Provenance and Build Integrity

SLSA (Supply-chain Levels for Software Artifacts, pronounced "salsa") is a framework for ensuring the integrity of software artifacts throughout the build and delivery process. SLSA defines four levels of increasing assurance:

For agent sandbox images, SLSA Level 3 is a practical target. GitHub Actions and Google Cloud Build both support SLSA Level 3 provenance generation through the slsa-github-generator and slsa-verifier tools. The provenance document records which source repository was built, which commit was checked out, which builder was used, and which build steps were executed. This document is signed and attached to the container image as an in-toto attestation.

# .github/workflows/build-agent-runner.yml
# GitHub Actions workflow with SLSA Level 3 provenance
name: Build Agent Runner
on:
 push:
 branches: [main]
jobs:
 build:
 runs-on: ubuntu-latest
 permissions:
 contents: read
 packages: write
 id-token: write # Required for keyless signing
 steps:
 - uses: actions/checkout@v4
 - name: Build container image
 run: |
 docker build -t registry.example.com/agent-runner:${{ github.sha }} .
 - name: Generate SBOM
 uses: anchore/sbom-action@v0
 with:
 image: registry.example.com/agent-runner:${{ github.sha }}
 format: cyclonedx-json
 output-file: sbom.cdx.json
 - name: Scan for vulnerabilities
 uses: aquasecurity/trivy-action@master
 with:
 image-ref: registry.example.com/agent-runner:${{ github.sha }}
 severity: CRITICAL,HIGH
 exit-code: "1"
 - name: Push image
 run: docker push registry.example.com/agent-runner:${{ github.sha }}
 - name: Sign image and attach SBOM
 uses: sigstore/cosign-installer@v3
 - run: |
 cosign sign registry.example.com/agent-runner:${{ github.sha }}
 cosign attest --predicate sbom.cdx.json --type cyclonedx \
 registry.example.com/agent-runner:${{ github.sha }}
 provenance:
 needs: build
 uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
 with:
 image: registry.example.com/agent-runner
 digest: ${{ needs.build.outputs.digest }}
Code Fragment 49.4.5: GitHub Actions workflow that builds an agent-runner image with SLSA Level 3 provenance. The pipeline generates an SBOM (Syft via sbom-action), scans for vulnerabilities (Trivy), signs the image (Cosign), attaches the SBOM as an attestation, and generates SLSA provenance.
Key Takeaways

What Comes Next

Per-artifact hardening is necessary but not sufficient. The build pipeline itself must be tamper-evident, and the model hubs you pull weights from must be scanned. Continue in Section 49.4a: SLSA, CI Hardening & Model-Hub Scanning.

Further Reading

Supply-Chain Security

SLSA Working Group. (2023). "Supply-chain Levels for Software Artifacts (SLSA) Framework v1.0." slsa.dev
Cox, R. (2019). "Surviving Software Dependencies." Communications of the ACM, 62(9). doi:10.1145/3349333