npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
Overview
Build-provenance verification answers a question that defeats many supply-chain attacks: was this artifact actually built from the source I think it was, by the builder I trust, without tampering? Attackers who compromise a build system, swap a compiled release, or inject a malicious step (as in the SolarWinds and 3CX incidents) produce artifacts that look legitimate but lack verifiable provenance. SLSA (Supply-chain Levels for Software Artifacts, https://slsa.dev) defines Build levels (L1–L3) describing increasing provenance integrity, and Sigstore (https://www.sigstore.dev) provides the signing and transparency infrastructure: cosign for signing/verifying artifacts and attestations, Fulcio for short-lived keyless certificates bound to an OIDC identity, and Rekor as a tamper-evident transparency log.
This skill covers verifying signatures and SLSA provenance with cosign (cosign verify, cosign verify-attestation, cosign verify-blob-attestation) and slsa-verifier (slsa-verifier verify-artifact), enforcing the builder identity (the GitHub Actions workflow that produced the artifact) and the expected source repository. Keyless verification ties trust to an OIDC issuer (e.g., https://token.actions.githubusercontent.com) and a certificate identity rather than a long-lived private key.
This maps to MITRE ATT&CK T1195 — Supply Chain Compromise (provenance verification detects/blocks tampered artifacts) and NIST CSF PR.DS-06 (integrity-checking mechanisms are used to verify software, firmware, and information integrity).
When to Use
- In CI/CD before deploying or promoting any container image or release binary.
- When consuming third-party artifacts (base images, Go/npm releases) that publish attestations.
- When establishing a SLSA Build L3 producer pipeline and enforcing it at the consumer side.
- During incident response to confirm whether a deployed artifact's provenance is intact.
- In admission control (e.g., Kubernetes via policy-controller / Kyverno) to admit only verified images.
Prerequisites
- cosign (Sigstore CLI):
go install github.com/sigstore/cosign/v2/cmd/cosign@latest # or download a release binary from https://github.com/sigstore/cosign/releases - slsa-verifier:
go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest # or: curl -sSL https://github.com/slsa-framework/slsa-verifier/releases/latest/download/slsa-verifier-linux-amd64 \ -o /usr/local/bin/slsa-verifier && chmod +x /usr/local/bin/slsa-verifier - Network access to Rekor (
https://rekor.sigstore.dev) and Fulcio for transparency-log verification. - The artifact plus its provenance/attestation bundle (
.sigstore,.intoto.jsonl, or attached OCI attestation).
Objectives
- Verify a keyless cosign signature on a container image, pinning OIDC issuer and certificate identity.
- Verify a SLSA provenance attestation on an image with
cosign verify-attestation --type slsaprovenance. - Verify a release binary's provenance with
slsa-verifier verify-artifact, pinning source repo and tag. - Verify GitHub artifact attestations / blob bundles with
cosign verify-blob-attestation. - Gate CI and admission control on successful verification; understand SLSA Build L1–L3.
MITRE ATT&CK Mapping
| ID | Tactic | Technique Name | Relevance |
|---|---|---|---|
| T1195 | Initial Access | Supply Chain Compromise | Verifying provenance and signatures detects artifacts that were tampered with or substituted in the build/distribution chain, preventing supply-chain compromise from reaching deployment. |
Workflow
Step 1: Verify a keyless cosign signature on an image
Pin both the OIDC issuer and the certificate identity (the exact workflow that signed). A bare cosign verify without identity pinning is meaningless — anyone can sign.
cosign verify \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--certificate-identity-regexp "^https://github.com/myorg/myrepo/.github/workflows/.*@refs/tags/v.*" \
ghcr.io/myorg/myrepo:v1.2.3A non-zero exit or empty result means verification failed — do not deploy.
Step 2: Verify the SLSA provenance attestation on the image
The signature proves who signed; the provenance attestation proves how it was built. Verify the in-toto SLSA predicate type.
cosign verify-attestation \
--type slsaprovenance \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--certificate-identity "https://github.com/myorg/myrepo/.github/workflows/build-sign.yml@refs/heads/main" \
ghcr.io/myorg/myrepo:v1.2.3Supported predicate types include slsaprovenance, slsaprovenance02, and slsaprovenance1.
Step 3: Inspect the provenance predicate
Decode the verified attestation to confirm the source repo, commit, and builder match expectations.
cosign verify-attestation --type slsaprovenance \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--certificate-identity-regexp '.*' \
ghcr.io/myorg/myrepo:v1.2.3 \
| jq -r '.payload' | base64 -d | jq '.predicate.buildDefinition.externalParameters, .predicate.runDetails.builder.id'Step 4: Verify a release binary with slsa-verifier
For downloadable binaries (e.g., produced by slsa-github-generator), pin the source URI and the tag. slsa-verifier checks the cryptographic signature on the provenance and that the expected builder produced it.
slsa-verifier verify-artifact slsa-test-linux-amd64 \
--provenance-path slsa-test-linux-amd64.intoto.jsonl \
--source-uri github.com/myorg/myrepo \
--source-tag v1.2.3
# Optionally pin the builder identity (SLSA L3)
slsa-verifier verify-artifact ./mybin \
--provenance-path ./mybin.intoto.jsonl \
--source-uri github.com/myorg/myrepo \
--builder-id https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v2.0.0Step 5: Verify GitHub artifact attestations / blob bundles
For artifacts signed via actions/attest-build-provenance, the bundle uses the new Sigstore bundle format.
cosign verify-blob-attestation \
--bundle ./myartifact.sigstore.json \
--new-bundle-format \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
--certificate-identity-regexp="^https://github.com/myorg/myrepo/" \
./myartifact
# Equivalent native GitHub CLI verification
gh attestation verify ./myartifact --repo myorg/myrepoStep 6: Enforce verification as a gate
Wrap verification so the pipeline fails closed on any error.
#!/usr/bin/env bash
set -euo pipefail
IMG="ghcr.io/myorg/myrepo:v1.2.3"
cosign verify \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--certificate-identity-regexp "^https://github.com/myorg/myrepo/" "$IMG" >/dev/null
cosign verify-attestation --type slsaprovenance \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--certificate-identity-regexp "^https://github.com/myorg/myrepo/" "$IMG" >/dev/null
echo "[+] $IMG verified: signature + SLSA provenance OK"Step 7: Map findings to SLSA Build levels
Document the level each consumed artifact achieves:
- Build L1 — provenance exists (the build process generates it), but it may be unsigned/forgeable.
- Build L2 — provenance is signed by a hosted build service.
- Build L3 — provenance is non-forgeable: generated on an isolated, hardened builder where secrets are unavailable to user-defined steps (e.g.,
slsa-github-generatorreusable workflows). Require L3 for high-trust artifacts.
Tools and Resources
| Tool / Resource | Purpose | Link |
|---|---|---|
| cosign | Sign/verify artifacts and attestations (keyless) | https://github.com/sigstore/cosign |
| slsa-verifier | Verify SLSA provenance from compliant builders | https://github.com/slsa-framework/slsa-verifier |
| slsa-github-generator | Produce SLSA L3 provenance in GitHub Actions | https://github.com/slsa-framework/slsa-github-generator |
| actions/attest-build-provenance | GitHub-native provenance attestation | https://github.com/actions/attest-build-provenance |
| SLSA specification | Build levels and provenance schema | https://slsa.dev/spec/v1.0/ |
| Sigstore docs | Fulcio, Rekor, cosign verification | https://docs.sigstore.dev/cosign/verifying/verify/ |
Verification Identity Reference
| Field | Where it comes from | Why it matters |
|---|---|---|
--certificate-oidc-issuer |
The OIDC issuer (e.g., GitHub Actions) | Restricts who could have requested the signing cert |
--certificate-identity[-regexp] |
The exact/patterned workflow identity (SAN) | Restricts which workflow signed; prevents impersonation |
--source-uri (slsa-verifier) |
Expected source repo | Confirms the artifact came from your repo |
--source-tag / --source-versioned-tag |
Expected git tag | Prevents rollback/substitution |
--builder-id |
Trusted builder workflow ref | Enforces SLSA L3 non-forgeable builder |
Validation Criteria
- cosign and slsa-verifier installed and report versions
- Image signature verified with pinned OIDC issuer AND certificate identity
- SLSA provenance attestation verified (
--type slsaprovenance) - Provenance predicate inspected; source repo/commit/builder match
- Release binary verified with slsa-verifier (source-uri + tag pinned)
- GitHub blob/bundle attestation verified
- Verification wired as a fail-closed CI/admission gate
- Each consumed artifact assigned a SLSA Build level
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 2
api-reference.md2.4 KB
cosign & slsa-verifier CLI Reference
Sources:
- https://github.com/sigstore/cosign
- https://github.com/slsa-framework/slsa-verifier
- https://docs.sigstore.dev/cosign/verifying/verify/
cosign — verification commands
| Command | Purpose |
|---|---|
cosign verify <image> |
Verify image signature(s) |
cosign verify-attestation <image> |
Verify in-toto attestation attached to image |
cosign verify-blob <file> |
Verify a detached signature on a blob |
cosign verify-blob-attestation <file> |
Verify an attestation bundle for a blob |
cosign download attestation <image> |
Pull attestations for offline inspection |
cosign tree <image> |
Show signatures/attestations attached to an image |
cosign — key verification flags
| Flag | Meaning |
|---|---|
--certificate-oidc-issuer <url> |
Required keyless: OIDC issuer that minted the cert |
--certificate-identity <san> |
Exact certificate identity (workflow SAN) |
--certificate-identity-regexp <re> |
Regex form of identity |
--type <type> |
Predicate type: slsaprovenance, slsaprovenance02, slsaprovenance1, spdx, cyclonedx, vuln, custom |
--bundle <file> |
Sigstore bundle for blob attestation |
--new-bundle-format |
Use the new Sigstore bundle format |
--key <path> |
Verify with a fixed public key (non-keyless) |
--rekor-url <url> |
Transparency log (default https://rekor.sigstore.dev) |
GitHub OIDC issuer (constant)
https://token.actions.githubusercontent.comslsa-verifier
| Command | Purpose |
|---|---|
slsa-verifier verify-artifact <artifact> |
Verify provenance for a binary/artifact |
slsa-verifier verify-image <image> |
Verify provenance for a container image |
slsa-verifier verify-npm-package <tarball> |
Verify npm package provenance |
slsa-verifier flags
| Flag | Meaning |
|---|---|
--provenance-path <file> |
Path to provenance (.intoto.jsonl / .sigstore) |
--source-uri <repo> |
Expected source repository (GitHub URIs) |
--source-tag <tag> |
Expected git tag |
--source-versioned-tag <tag> |
Semver-aware tag match |
--builder-id <ref> |
Pin the trusted builder workflow (SLSA L3) |
--print-provenance |
Print the verified provenance to stdout |
GitHub CLI native verification
| Command | Purpose |
|---|---|
gh attestation verify <artifact> --repo <org>/<repo> |
Verify GitHub-generated build provenance |
standards.md1.4 KB
Standards Mapping — Verifying Build Provenance with SLSA and Sigstore
MITRE ATT&CK
| ID | Technique Name | Rationale |
|---|---|---|
| T1195 | Supply Chain Compromise | Verifying signatures and SLSA provenance detects artifacts tampered with or substituted anywhere in the build and distribution chain, blocking supply-chain compromise before deployment. Ref: https://attack.mitre.org/techniques/T1195/ |
NIST Cybersecurity Framework 2.0
| ID | Subcategory | Rationale |
|---|---|---|
| PR.DS-06 | Integrity-checking mechanisms are used to verify software, firmware, and information integrity | cosign signature verification and SLSA provenance verification are integrity-checking mechanisms that cryptographically confirm an artifact was built from the expected source by the expected builder and was not modified. |
SLSA Build Levels
| Level | Guarantee |
|---|---|
| Build L1 | Provenance exists (may be forgeable) |
| Build L2 | Provenance signed by a hosted build service |
| Build L3 | Non-forgeable provenance from a hardened, isolated builder |
Ref: https://slsa.dev/spec/v1.0/levels
Supporting References
- Sigstore architecture (Fulcio short-lived certs, Rekor transparency log): https://docs.sigstore.dev/
- slsa-github-generator (L3 producer): https://github.com/slsa-framework/slsa-github-generator
Scripts 1
agent.py4.7 KB
#!/usr/bin/env python3
"""
provenance-verify — verify Sigstore signatures and SLSA provenance, fail closed.
Wraps the real cosign and slsa-verifier CLIs:
- cosign: https://github.com/sigstore/cosign
- slsa-verifier: https://github.com/slsa-framework/slsa-verifier
Install the binaries first:
go install github.com/sigstore/cosign/v2/cmd/cosign@latest
go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest
Examples:
python agent.py image \
--image ghcr.io/myorg/myrepo:v1.2.3 \
--oidc-issuer https://token.actions.githubusercontent.com \
--identity-regexp '^https://github.com/myorg/myrepo/'
python agent.py artifact \
--artifact ./mybin \
--provenance ./mybin.intoto.jsonl \
--source-uri github.com/myorg/myrepo \
--source-tag v1.2.3
"""
import argparse
import base64
import json
import shutil
import subprocess
import sys
GITHUB_OIDC = "https://token.actions.githubusercontent.com"
def _require(tool: str) -> None:
if shutil.which(tool) is None:
sys.exit(f"error: '{tool}' not found on PATH. See the skill prerequisites.")
def _run(argv: list, capture: bool = False) -> subprocess.CompletedProcess:
print(f"[*] {' '.join(argv)}", file=sys.stderr)
return subprocess.run(argv, capture_output=capture, text=True)
def verify_image(args) -> int:
_require("cosign")
issuer = args.oidc_issuer
# 1) signature
sig = ["cosign", "verify",
"--certificate-oidc-issuer", issuer]
if args.identity:
sig += ["--certificate-identity", args.identity]
else:
sig += ["--certificate-identity-regexp", args.identity_regexp]
sig.append(args.image)
if _run(sig).returncode != 0:
print("[!] signature verification FAILED", file=sys.stderr)
return 1
print("[+] signature OK", file=sys.stderr)
# 2) SLSA provenance attestation
att = ["cosign", "verify-attestation", "--type", args.predicate_type,
"--certificate-oidc-issuer", issuer]
if args.identity:
att += ["--certificate-identity", args.identity]
else:
att += ["--certificate-identity-regexp", args.identity_regexp]
att.append(args.image)
proc = _run(att, capture=True)
if proc.returncode != 0:
print("[!] provenance verification FAILED", file=sys.stderr)
print(proc.stderr, file=sys.stderr)
return 1
print("[+] SLSA provenance OK", file=sys.stderr)
# 3) decode and surface key provenance fields
try:
payload = json.loads(proc.stdout.splitlines()[0])["payload"]
decoded = json.loads(base64.b64decode(payload))
pred = decoded.get("predicate", {})
builder = (pred.get("runDetails", {}).get("builder", {}).get("id")
or pred.get("builder", {}).get("id"))
print(json.dumps({"image": args.image, "verified": True,
"builder_id": builder}, indent=2))
except Exception:
print(json.dumps({"image": args.image, "verified": True}, indent=2))
return 0
def verify_artifact(args) -> int:
_require("slsa-verifier")
argv = ["slsa-verifier", "verify-artifact", args.artifact,
"--provenance-path", args.provenance,
"--source-uri", args.source_uri]
if args.source_tag:
argv += ["--source-tag", args.source_tag]
if args.builder_id:
argv += ["--builder-id", args.builder_id]
rc = _run(argv).returncode
if rc != 0:
print("[!] artifact provenance verification FAILED", file=sys.stderr)
return 1
print(json.dumps({"artifact": args.artifact, "verified": True,
"source_uri": args.source_uri,
"source_tag": args.source_tag}, indent=2))
return 0
def main() -> int:
p = argparse.ArgumentParser(description="Verify Sigstore signatures and SLSA provenance.")
sub = p.add_subparsers(dest="cmd", required=True)
im = sub.add_parser("image", help="verify container image signature + provenance")
im.add_argument("--image", required=True)
im.add_argument("--oidc-issuer", default=GITHUB_OIDC)
g = im.add_mutually_exclusive_group(required=True)
g.add_argument("--identity")
g.add_argument("--identity-regexp")
im.add_argument("--predicate-type", default="slsaprovenance")
im.set_defaults(func=verify_image)
ar = sub.add_parser("artifact", help="verify binary/artifact provenance via slsa-verifier")
ar.add_argument("--artifact", required=True)
ar.add_argument("--provenance", required=True)
ar.add_argument("--source-uri", required=True)
ar.add_argument("--source-tag")
ar.add_argument("--builder-id")
ar.set_defaults(func=verify_artifact)
args = p.parse_args()
return args.func(args)
if __name__ == "__main__":
sys.exit(main())