← Security

Supply chain

Provenance, vulnerability scanning, and image pinning — how gittan protects your software supply chain.

Provenance

Every pipeline that publishes a container image automatically generates a SLSA v1 provenance attestation. This is not opt-in. If you publish an image through gittan, it gets provenance.

gittan uses a two-layer signing scheme: the platform key signs an ephemeral certificate for the run, and the ephemeral key signs the attestation. The private key exists only for the duration of the pipeline run. A compromised runner cannot sign future builds.

Attestations are pushed as OCI referrer artifacts alongside the image, following the OCI 1.1 Referrers API. The verify-provenance step runs automatically after publish.

Secret scanning

Every push is scanned for hardcoded secrets using gitleaks. API keys, tokens, private keys, and other credentials are detected automatically. If secrets are found, the push is blocked — no bypass, no override, no emergency exception.

The scanner excludes node_modules, vendor, .pnpm-store, and .yarn directories. If a finding is a false positive, the right fix is a gitleaks allowlist in your repo, not a platform bypass.

Vulnerability scanning

gittan runs Trivy on every push as a platform policy. CRITICAL CVEs block the push — the pipeline fails and the developer sees what needs fixing. HIGH findings are reported but do not block. Scans produce structured output that gittan parses into per-repo findings visible in the team's security view.

Reachability analysis

A CVE in a package you depend on is not the same as a CVE in code you actually call. gittan's dependency scanner includes LLM-powered reachability analysis that goes beyond severity ratings: it identifies which source files import the vulnerable package, analyzes whether the vulnerable function is actually invoked, and checks whether user-controlled data reaches it.

Reachable vulnerabilities with a fix available block the push. Unreachable vulnerabilities are downgraded to informational — tracked in the team's security view but not blocking. When the analysis cannot determine reachability (LLM unavailable or low confidence), findings fall back to severity-based classification.

See security findings for the full reachability classification table.

Policy scan

Every push also runs a static analysis pass that checks for security anti-patterns and tooling choices. This scan is advisory — it reports findings but never blocks the push. Findings go to the team's security view.

The policy scan flags patterns like:

  • LLM response passed to eval() or exec() — code injection risk
  • User input interpolated into LLM prompts — prompt injection risk
  • innerHTML assignments — XSS risk
  • String interpolation in database queries — SQL injection risk
  • Privileged containers or privilege escalation in Kubernetes manifests
  • :latest tags in Dockerfiles

Container image scanning

When a pipeline publishes a container image, gittan automatically runs Trivy against the published image. This catches vulnerabilities in OS packages, system libraries, and anything else baked into the image that dependency scanning cannot see.

CRITICAL image CVEs block the push, same as dependency scanning. HIGH findings go to the team's security view.

Image provenance chain

gittan base images (gittan/node:24, gittan/python:3.14, etc.) are built with a verified chain from upstream to your pipeline:

StageWhat happensIf verification fails
1. Upstream pullOfficial image pulled from Docker Hub (e.g. node:24-alpine). Cosign verifies the upstream Sigstore signature before the build starts.Image is not pulled. Build aborted.
2. gittan buildgittan layers its base tools on top. The build pipeline signs the resulting image using keyless Sigstore signing — the signing identity is the pipeline's OIDC workload token from auth.gittan.eu.—
3. Registry pushSigned image and SLSA provenance attestation are pushed to images.gittan.eu as OCI referrer artifacts.—
4. Runtime verifyBefore running any pipeline step, the runner verifies the image signature against gittan's OIDC issuer. Every pull is verified, every time.Step does not run. Pipeline rejected.

No key management. The signing identity is the pipeline run's short-lived OIDC token, verified through Sigstore's transparency log. Anyone can verify that a gittan/* image was built by gittan's CI — not manually pushed, not tampered with after build.

Requiring provenance for all images

gittan base images are always verified. For everything else, org owners can enforce provenance verification as an org-level policy:

# org-pipelines/policies/require-provenance.yaml
description: Reject unsigned container images in all pipelines
enabled: true
match:
  all: true
settings:
  require-image-provenance: true
  trusted-issuers:
    - https://auth.gittan.eu            # gittan CI
    - https://accounts.google.com       # Docker official images
    - https://token.actions.githubusercontent.com  # GitHub Actions

When enabled, the pipeline runner verifies the cosign signature on every image before running the step. The behavior per image type:

Image sourceSigned byResult
gittan/node:24gittan CI (auth.gittan.eu)Passes
images.gittan.eu/myorg/myapp:1.0Team's pipeline (auth.gittan.eu)Passes — same OIDC issuer
node:24-alpineDocker (accounts.google.com)Passes — if issuer is in trusted list
random/tool:latestNot signedRejected — no signature found
evil.registry.io/backdoor:1Signed by unknown issuerRejected — issuer not in trusted list

The trusted-issuers list controls which OIDC issuers are accepted. Only add issuers you trust to produce images your teams should run. Teams cannot override this — it is enforced at the pipeline runtime level, not in the image or the step configuration.

# Verify any image manually
cosign verify images.gittan.eu/myorg/myimage:1.0 \
  --certificate-oidc-issuer https://auth.gittan.eu

Image pinning

No :latest tag is allowed. Vetted images are pinned by digest. User images must be pinned. A mutable tag is a supply chain attack waiting to happen.