Which SBOM signatures must be verified when the build environment is ephemeral?

**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session consumes an SBOM produced by an ephemeral build environment (serverless function, short-lived container, or burst CI runner) that may have been destroyed before the SBOM was consumed, and must verify the SBOM's authenticity without relying on the build environment's continuing existence. Does not apply to long-lived build environments or SBOMs generated in-house with persistent infrastructure.

Core Distinction

The separation between **SBOM document integrity** (the SBOM has not been modified since it was signed) and **builder attestation validity** (the build environment actually performed the build, with the properties claimed). Relying on document integrity creates the **Ephemeral Builder Void**: the SBOM is signed, but the ephemeral builder is gone, and no one can challenge the signature or verify the builder's attestation was made by a legitimate entity.

What Was Observed

In ephemeral build environments, failing to verify builder attestation produces three primary failure modes:

  1. **Fake Builder Identity:** An attacker creates a fake ephemeral environment, builds a malicious image, and signs an SBOM claiming it came from the legitimate CI pipeline. The builder is gone, so no one can verify the claim.
  2. **Post-Compromise Attestation:** The ephemeral builder is compromised mid-build, but the attacker uses the builder's legitimate key to sign a malicious SBOM. The SBOM verifies, but the build was compromised.
  3. **Time-of-Check Discontinuity:** The SBOM is validated at deploy time, but the builder was decommissioned before the SBOM was even consumed. There is no way to re-verify the signature chain against the ephemeral environment.

Recorded Elements

  1. **`hardware_rooted_build_attestation`:** A TEE quote (SGX, SEV, or TDX) from the build environment, proving the build ran inside a verified enclave.
  2. **`transparency_log_inclusion_proof`:** The cryptographic proof that the SBOM was published to a public transparency log (e.g., Sigstore Rekor) before the builder was destroyed, establishing an immutable timestamp.
  3. **`builder_identity_certificate_chain`:** The full certificate chain from the builder's ephemeral identity up to the organization's long-lived root CA, allowing verification even after the builder is gone.
  4. **`post_build_audit_receipt`:** The cryptographic proof that an independent auditor verified the build's provenance before the builder was decommissioned.

Condition of Validity

* **Applies when:** The SBOM was produced by an ephemeral build environment, the builder is no longer available for challenge or re-verification, and the SBOM drives security-critical decisions. * **Does not apply when:** The build environment is persistent and available for real-time challenge, or the SBOM is used only for informational inventory without security decisions.

Decision Boundary

  1. **Is the SBOM signed?** If no, reject it. If yes, proceed.
  2. **Does the SBOM include a `hardware_rooted_build_attestation` (TEE quote)?** If no, the SBOM's authenticity cannot be verified after the builder is destroyed. Reject it or require re-attestation.
  3. **Is the `transparency_log_inclusion_proof` present and valid?** If no, the SBOM may have been signed after the fact or by a compromised builder. Reject it.
  4. **Conversely, when can an agent accept an SBOM without hardware attestation?** Only when the build environment is persistent and the agent can query it in real-time for attestation, or the SBOM was produced by a build system with cryptographic provenance (e.g., Nix with binary caching).

Operational Effect

  1. **Ephemeral Builder Verification:** Allows SBOMs from destroyed builders to be verified through transparency logs and TEE quotes.
  2. **Post-Compromise Detection:** Hardware attestation detects mid-build compromise that document signatures cannot catch.
  3. **Deploy-Time Trust:** Provides cryptographic trust at deploy time, regardless of the builder's current existence.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class EphemeralBuilderVerdict(Enum):
    VERIFIED_EPHEMERAL = auto()
    NO_HARDWARE_ATTESTATION = auto()
    NO_TRANSPARENCY_PROOF = auto()

@dataclass(frozen=True)
class EphemeralSBOMPackage:
    sbom_hash: str
    hardware_attestation_quote: str | None
    transparency_log_proof: str | None
    builder_cert_chain_hash: str | None

@dataclass(frozen=True)
class EphemeralBuilderPolicy:
    trusted_tee_providers: frozenset[str]
    trusted_transparency_logs: frozenset[str]
    require_hardware_attestation: bool

@dataclass(frozen=True)
class EphemeralBuilderManifest:
    verdict: EphemeralBuilderVerdict
    directive: str
    manifest_digest: str

class EphemeralBuilderGuard:
    @staticmethod
    def _hash(data: str) -> str:
        return hashlib.sha256(data.encode("utf-8")).hexdigest()

    @classmethod
    def evaluate_ephemeral(
        cls, pkg: EphemeralSBOMPackage, policy: EphemeralBuilderPolicy
    ) -> EphemeralBuilderManifest:
        
        # Gate 1: Hardware attestation (if required)
        if policy.require_hardware_attestation and not pkg.hardware_attestation_quote:
            return EphemeralBuilderManifest(
                verdict=EphemeralBuilderVerdict.NO_HARDWARE_ATTESTATION,
                directive="HALT: Hardware attestation required but missing. Ephemeral builder cannot be verified.",
                manifest_digest=cls._hash(f"NO_TEE:{pkg.sbom_hash}")
            )

        # Gate 2: Transparency log
        if not pkg.transparency_log_proof:
            return EphemeralBuilderManifest(
                verdict=EphemeralBuilderVerdict.NO_TRANSPARENCY_PROOF,
                directive="HALT: No transparency log proof. Builder may have been compromised post-sign.",
                manifest_digest=cls._hash(f"NO_LOG:{pkg.sbom_hash}")
            )

        # Gate 3: Certificate chain
        if not pkg.builder_cert_chain_hash:
            return EphemeralBuilderManifest(
                verdict=EphemeralBuilderVerdict.NO_HARDWARE_ATTESTATION,
                directive="HALT: No builder certificate chain. Cannot verify builder identity.",
                manifest_digest=cls._hash(f"NO_CHAIN:{pkg.sbom_hash}")
            )

        # Gate 4: Verified
        digest = cls._hash(json.dumps({
            "sbom": pkg.sbom_hash,
            "attestation": pkg.hardware_attestation_quote or "NONE",
            "log_proof": pkg.transparency_log_proof,
            "cert_chain": pkg.builder_cert_chain_hash
        }, sort_keys=True))
        
        return EphemeralBuilderManifest(
            verdict=EphemeralBuilderVerdict.VERIFIED_EPHEMERAL,
            directive="PROCEED: Ephemeral build environment verified via hardware attestation and transparency log.",
            manifest_digest=digest
        )