Explanation

Security Model

How Evidence Packs use cryptographic digests and Sigstore signatures to provide security guarantees.

Core Security Principles

epack is designed with security as a primary concern. The tool handles sensitive compliance evidence and must protect both the integrity of packs and the credentials used during collection.

Design Principles

  • Cryptographic Integrity: SHA-256 digests for all artifacts
  • Provenance Verification: Sigstore signatures with identity binding
  • Least Privilege: Only specified secrets passed to collectors
  • Defense in Depth: Multiple validation layers
  • Fail Secure: Default to strictest verification mode

Integrity Verification

Every Evidence Pack includes cryptographic integrity guarantees through artifact digests. Run epack verify --integrity-only to check digests without requiring signatures.

How artifact digests work

Each artifact's SHA-256 hash is computed and recorded in the manifest when you run epack build. During epack verify, the hash is recomputed and compared. Any modification to the artifact will produce a different hash, causing verification to fail.

Terminal
# Verify integrity only (no signature required)
$ epack verify --integrity-only evidence.pack

 Pack integrity verified
  Pack digest: sha256:a3f2b8c9d4e5f6...
  Artifacts: 12 verified
  No attestations present
manifest.json (excerpt)
{
  "artifacts": [
    {
      "path": "artifacts/soc2-report.pdf",
      "digest": "sha256:a3f2b8c9d4e5f6...",
      "size": 1048576
    }
  ]
}

Pack digest

The pack_digest is a hash of all artifact paths and their individual digests, providing a single value that covers the entire pack contents. This is what gets signed, so a single signature authenticates all artifacts. View it with epack inspect:

$ epack inspect evidence.pack --format json | jq .pack_digest
"sha256:a3f2b8c9d4e5f6a7b8c9d0e1f2..."

What integrity verification detects

  • Any modification to artifact content
  • Addition or removal of artifacts
  • Renaming artifacts
  • Manifest tampering (causes pack_digest mismatch)

Sigstore Signing

epack uses Sigstore for signing via epack sign. Keyless signatures are tied to OIDC identities, eliminating key management while providing strong provenance guarantees.

Terminal
# Sign a pack (opens browser for authentication)
$ epack sign evidence.pack

Opening browser for authentication...
Authenticated as: security@vendor.com (Google)

 Pack signed successfully
  Signer: security@vendor.com
  Issuer: https://accounts.google.com
  Rekor entry: https://rekor.sigstore.dev/api/v1/log/entries/...

How Sigstore signing works

  1. User authenticates via OIDC (Google, GitHub, Microsoft, etc.)
  2. Fulcio issues a short-lived certificate (~10 minutes)
  3. The certificate embeds the authenticated identity
  4. The manifest digest is signed with the temporary key
  5. The signature is recorded in the Rekor transparency log
  6. The complete bundle is stored in the pack

What's in an attestation bundle

Each attestation stored in the pack includes:

  • The digital signature over the manifest digest
  • The signing certificate with identity claims
  • The certificate chain to Fulcio root
  • The Rekor transparency log entry
  • Timestamp (optional, for long-term verification)

View attestation details with epack inspect:

$ epack inspect evidence.pack --attestations

Attestations (1):
  [0] Sigstore Bundle
      Subject: security@vendor.com
      Issuer:  https://accounts.google.com
      Signed:  2024-02-15T10:30:00Z
      Rekor:   24296fb24b8ad77a...

CI/CD signing with OIDC

When signing in CI/CD, set EPACK_OIDC_TOKEN to your workflow's OIDC token. The Sigstore certificate embeds additional claims about the source:

GitHub Actions
- name: Sign pack
  env:
    EPACK_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
  run: epack sign evidence.pack

The certificate includes:

  • The commit SHA that triggered the workflow
  • The repository URL
  • The workflow path
  • The ref (branch or tag)

This means the signature proves exactly which code generated the evidence. Verifiers can check the exact immutable version that ran.

Threat Model

In scope (what epack protects against)

  • Tampered packs: Detecting modifications to artifacts or manifest
  • Forged signatures: Rejecting invalid or unauthorized attestations
  • Malicious collectors: Preventing arbitrary code execution from untrusted sources (via lockfile verification)
  • Secret leakage: Protecting credentials from exposure in logs or errors
  • Path traversal: Preventing extraction outside target directory

Out of scope

  • Physical access to the machine running epack
  • Compromise of your OIDC identity provider
  • Compromise of Sigstore infrastructure
  • Side-channel attacks during cryptographic operations

Security non-goals

  • Validating the accuracy of evidence (only integrity)
  • Preventing authorized users from creating misleading packs
  • Sandboxing collectors beyond environment isolation

Two Editions, Different Security Profiles

epack comes in two editions with different security profiles:

epack-core Minimal Attack Surface
  • No subprocess execution
  • No binary downloads
  • No network requests (except Sigstore)
  • Read/write local files only
  • Ideal for verification pipelines
epack (full) Extended Capabilities
  • Downloads collector binaries
  • Executes collectors as subprocesses
  • Manages credentials via environment
  • Requires lockfile verification
  • Use --frozen mode in CI
Recommendation: Use epack-core for verification-only workflows. Use the full edition only when automated collection is required.

Collector Security

The full edition downloads and executes collector binaries, which requires careful security controls.

Binary verification

  • Collectors are downloaded from GitHub releases
  • SHA-256 digest is recorded in lockfile
  • Digest is verified before execution
  • Signer identity is verified via Sigstore

Environment isolation

  • Only explicitly listed secrets are passed to collectors
  • Reserved environment prefixes are blocked (EPACK_, LD_, etc.)
  • Collectors cannot access other environment variables

Lockfile security

The lockfile (epack.lock.yaml) provides reproducible builds by pinning exact versions, platform-specific binary digests, and signer identities.

Important: Always use --frozen mode in CI/CD to ensure lockfile verification. This prevents unexpected changes to collector binaries.

Secret Management

Configuration

Secrets are specified in epack.yaml by name only. Values come from environment variables.

epack.yaml
collectors:
  github:
    source: locktivity/epack-collector-github@v1
    secrets:
      - GITHUB_TOKEN  # Only this secret is passed

Secret protection

  • Redaction: Error messages are redacted by default to prevent exposure
  • Secret scanning: The build command warns about potential secrets in artifacts
  • Minimal exposure: Only listed secrets are passed to collectors

Vulnerability Reporting

If you discover a security vulnerability in epack, please report it responsibly. Do not open public GitHub issues for security vulnerabilities.

Report security issues to: security@locktivity.com

See Also