npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
Authorized Use Only: Generate and scan SBOMs only for software and images you own or are authorized to assess. Treat SBOMs as sensitive inventory data — they reveal your dependency attack surface.
Overview
A Software Bill of Materials (SBOM) is a formal, machine-readable inventory of every component, library, and dependency in a piece of software — the supply-chain equivalent of an ingredients label. SBOMs are central to defending against supply-chain compromise (CISA's SBOM initiative, US Executive Order 14028) because you cannot patch what you cannot see. The two dominant SBOM standards are:
- CycloneDX — an OWASP standard optimized for security use cases (vulnerabilities, VEX, dependency relationships).
- SPDX — a Linux Foundation / ISO standard (ISO/IEC 5962) strong on licensing and provenance.
The reference open-source toolchain is from Anchore:
- Syft generates SBOMs (CycloneDX, SPDX, or its native format) from container images and filesystems.
- Grype matches an SBOM (or image) against vulnerability databases to find CVEs.
- Cosign (Sigstore) signs SBOMs and attaches them to images as signed attestations for tamper-evident provenance.
This skill covers producing standards-compliant SBOMs, correlating them with vulnerability intelligence, and embedding the workflow into CI/CD.
When to Use
- Establishing and maintaining a component inventory for applications and container images.
- Continuously detecting known vulnerabilities (including newly disclosed CVEs against existing artifacts).
- Satisfying procurement/regulatory SBOM requirements (CISA, EO 14028).
- Producing signed SBOM attestations for downstream supply-chain trust.
Prerequisites
- Install Syft and Grype (official install scripts):
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin - Install Cosign for signing/attestation:
# via Go, or download a release from https://github.com/sigstore/cosign/releases go install github.com/sigstore/cosign/v2/cmd/cosign@latest - Access to the target images/source and (for signing) a registry plus keys or keyless OIDC.
Objectives
- Generate CycloneDX and SPDX SBOMs from images and directories.
- Scan SBOMs and images for vulnerabilities with Grype.
- Gate CI/CD builds on severity thresholds.
- Sign and attach SBOM attestations with Cosign and verify them.
MITRE ATT&CK Mapping
| ID | Official Technique Name | Relevance to this skill |
|---|---|---|
| T1195.001 | Supply Chain Compromise: Compromise Software Dependencies and Development Tools | SBOM generation and vulnerability correlation expose compromised or vulnerable dependencies — the attack surface adversaries abuse under this technique. |
This is a defensive supply-chain skill; the mapping reflects the adversary technique it is designed to detect and mitigate.
Workflow
1. Generate a CycloneDX SBOM from a container image
-o <format> selects output; cyclonedx-json is security-oriented.
syft alpine:latest -o cyclonedx-json=alpine.cdx.json2. Generate an SPDX SBOM from a source directory
Use the dir: source to inventory a checked-out repository; spdx-json for the SPDX standard.
syft dir:. -o spdx-json=app.spdx.json3. Emit multiple formats at once
Produce both standards in a single pass for different consumers.
syft myorg/app:1.4.2 \
-o cyclonedx-json=app.cdx.json \
-o spdx-json=app.spdx.json \
-o table4. Scan the SBOM for vulnerabilities with Grype
Decoupling generation from scanning lets you re-scan stored SBOMs as new CVEs land — without rebuilding.
# Scan an existing SBOM
grype sbom:app.cdx.json -o table
# JSON report for automation
grype sbom:app.cdx.json -o json > app.vulns.jsonYou can also scan an image directly (Grype generates the SBOM internally):
grype myorg/app:1.4.2 -o table5. Gate CI/CD on severity
--fail-on exits non-zero at or above a severity, failing the pipeline.
grype sbom:app.cdx.json --fail-on highFilter out unfixable noise with a .grype.yaml policy (only-fixed: true) or --only-fixed:
grype sbom:app.cdx.json --only-fixed --fail-on critical6. Sign and attach the SBOM as an attestation
Cosign records the SBOM as a signed, in-toto attestation alongside the image in the registry.
# Key-based signing
cosign attest --key cosign.key \
--predicate app.spdx.json \
--type spdxjson \
myorg/app:1.4.2
# Keyless (Sigstore OIDC / Fulcio + Rekor)
COSIGN_EXPERIMENTAL=1 cosign attest \
--predicate app.cdx.json \
--type cyclonedx \
myorg/app:1.4.27. Verify the attestation downstream
Consumers verify provenance before trusting an image.
cosign verify-attestation --key cosign.pub --type spdxjson myorg/app:1.4.28. Retrieve and re-scan attached SBOMs
Pull the attested SBOM from the registry and re-run Grype as part of continuous monitoring.
cosign download attestation myorg/app:1.4.2 \
| jq -r '.payload' | base64 -d | jq '.predicate' > pulled.spdx.json
grype sbom:pulled.spdx.json -o table9. Correlate to vulnerability intelligence
Feed Grype JSON into your vulnerability management workflow: deduplicate by CVE, enrich with EPSS/KEV for prioritization, and track remediation SLAs. Re-scan stored SBOMs on each Grype DB update to catch newly disclosed CVEs in unchanged artifacts.
Tools and Resources
| Tool | Purpose | Link |
|---|---|---|
| Syft | SBOM generation | https://github.com/anchore/syft |
| Grype | Vulnerability scanning of SBOMs/images | https://github.com/anchore/grype |
| Cosign | SBOM signing/attestation | https://github.com/sigstore/cosign |
| CycloneDX | Security-focused SBOM standard | https://cyclonedx.org/ |
| SPDX | ISO SBOM standard | https://spdx.dev/ |
| CISA SBOM | Guidance and minimum elements | https://www.cisa.gov/sbom |
Format Comparison
| Aspect | CycloneDX | SPDX |
|---|---|---|
| Steward | OWASP | Linux Foundation / ISO 5962 |
| Strength | Security, VEX, vulnerabilities | Licensing, provenance |
Common syft -o values |
cyclonedx-json, cyclonedx-xml |
spdx-json, spdx (tag-value) |
Validation Criteria
- CycloneDX SBOM generated from the target image
- SPDX SBOM generated from source where required
- SBOM scanned with Grype producing a CVE report
- CI/CD gated with
--fail-onat an agreed severity - SBOM signed and attached as an attestation with Cosign
- Attestation verified downstream
- Stored SBOMs re-scanned on Grype DB updates
- Findings correlated/prioritized (EPSS/KEV) and tracked to remediation
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 2
api-reference.md2.3 KB
SBOM Toolchain Command Reference
Syft (SBOM generation)
Source prefixes: <image> (default = container image), dir:<path>, file:<path>,
registry:<image>, docker:<image>, oci-archive:<path>.
| Flag / form | Purpose |
|---|---|
-o <format>[=<file>] |
Output format and optional file |
--scope <squashed|all-layers> |
Layer scope for images |
--exclude <glob> |
Exclude paths |
syft <src> -o table |
Human-readable summary |
Common -o formats: cyclonedx-json, cyclonedx-xml, spdx-json, spdx (tag-value), syft-json, table.
syft alpine:latest -o cyclonedx-json=alpine.cdx.json
syft dir:. -o spdx-json=app.spdx.json
syft myorg/app:1.4.2 -o cyclonedx-json=app.cdx.json -o spdx-json=app.spdx.json -o tableGrype (vulnerability scanning)
Source prefixes: sbom:<file>, <image>, dir:<path>, registry:<image>.
| Flag | Purpose |
|---|---|
-o <format> |
table, json, cyclonedx, sarif |
--fail-on <severity> |
Exit non-zero at/above severity (low|medium|high|critical) |
--only-fixed |
Report only vulns with a fix available |
--add-cpes-if-none |
Improve matching for SBOMs lacking CPEs |
db update |
Update the vulnerability database |
grype sbom:app.cdx.json -o table
grype sbom:app.cdx.json -o json > app.vulns.json
grype sbom:app.cdx.json --only-fixed --fail-on critical
grype myorg/app:1.4.2 -o table
grype db updateCosign (signing / attestation)
| Command | Purpose |
|---|---|
cosign attest --key <key> --predicate <sbom> --type <type> <image> |
Attach signed SBOM attestation |
cosign verify-attestation --key <pub> --type <type> <image> |
Verify attestation |
cosign download attestation <image> |
Retrieve attached attestation |
cosign generate-key-pair |
Create signing keys |
--type values: spdxjson, cyclonedx, slsaprovenance, or a custom URI.
Keyless mode: set COSIGN_EXPERIMENTAL=1 and omit --key (uses Fulcio/Rekor).
cosign attest --key cosign.key --predicate app.spdx.json --type spdxjson myorg/app:1.4.2
cosign verify-attestation --key cosign.pub --type spdxjson myorg/app:1.4.2
cosign download attestation myorg/app:1.4.2Policy file (.grype.yaml)
only-fixed: true
fail-on-severity: high
ignore:
- vulnerability: CVE-2024-0000 # documented, risk-acceptedstandards.md1.4 KB
Standards and Framework Mapping — Generating and Analyzing SBOMs
NIST Cybersecurity Framework 2.0
| ID | Name | Rationale |
|---|---|---|
| ID.AM-08 | Systems, hardware, software, services, and data are managed throughout their life cycles | SBOMs are the authoritative software-component inventory that underpins lifecycle asset management and supply-chain risk visibility. |
MITRE ATT&CK
| ID | Name | Rationale |
|---|---|---|
| T1195.001 | Supply Chain Compromise: Compromise Software Dependencies and Development Tools | SBOM generation plus vulnerability correlation surfaces vulnerable/compromised dependencies, directly countering this technique. |
SBOM Standards and Authorities
| Standard / Authority | Role |
|---|---|
| CycloneDX (OWASP) | Security-focused SBOM format (VEX, vulnerabilities) |
| SPDX (ISO/IEC 5962) | Licensing/provenance-focused SBOM format |
| CISA SBOM Minimum Elements | Baseline required SBOM fields |
| US Executive Order 14028 | Mandates SBOMs for software sold to the US government |
| NTIA "Framing Software Component Transparency" | Foundational SBOM guidance |
Supporting References
- CISA SBOM: https://www.cisa.gov/sbom
- CycloneDX: https://cyclonedx.org/
- SPDX: https://spdx.dev/
- Syft: https://github.com/anchore/syft
- Grype: https://github.com/anchore/grype
- Sigstore Cosign: https://github.com/sigstore/cosign
Scripts 1
agent.py5.3 KB
#!/usr/bin/env python3
"""
SBOM generation + vulnerability correlation helper.
Wraps Syft (SBOM generation), Grype (vulnerability scanning), and Cosign
(attestation) with real flags. Can run the full pipeline (generate -> scan ->
optionally attest) and summarize Grype JSON by severity for CI gating.
References:
https://github.com/anchore/syft
https://github.com/anchore/grype
https://github.com/sigstore/cosign
"""
import argparse
import json
import shutil
import subprocess
import sys
from collections import Counter
SEVERITY_ORDER = ["negligible", "low", "medium", "high", "critical"]
def require(tool):
path = shutil.which(tool)
if not path:
print(f"[!] '{tool}' not found on PATH", file=sys.stderr)
return path
def run(cmd, dry_run, capture=False):
print("[*] " + " ".join(cmd), file=sys.stderr)
if dry_run:
return 0, ""
try:
if capture:
proc = subprocess.run(cmd, check=False, text=True, capture_output=True)
if proc.returncode != 0 and proc.stderr:
print(proc.stderr, file=sys.stderr)
return proc.returncode, proc.stdout
return subprocess.run(cmd, check=False).returncode, ""
except FileNotFoundError:
print(f"[!] command not found: {cmd[0]}", file=sys.stderr)
return 127, ""
def syft_generate(source, fmt, outfile, dry_run):
syft = require("syft") or "syft"
cmd = [syft, source, "-o", f"{fmt}={outfile}"]
rc, _ = run(cmd, dry_run)
return rc
def grype_scan(sbom_path, out_json, fail_on=None, only_fixed=False, dry_run=False):
grype = require("grype") or "grype"
cmd = [grype, f"sbom:{sbom_path}", "-o", "json"]
if only_fixed:
cmd.append("--only-fixed")
if fail_on:
cmd += ["--fail-on", fail_on]
rc, out = run(cmd, dry_run, capture=True)
if out and not dry_run:
with open(out_json, "w", encoding="utf-8") as fh:
fh.write(out)
return rc, out
def summarize(grype_json_text):
"""Count vulnerabilities by severity from Grype JSON output."""
try:
data = json.loads(grype_json_text)
except (json.JSONDecodeError, TypeError):
print("[!] could not parse Grype JSON", file=sys.stderr)
return Counter()
counts = Counter()
for match in data.get("matches", []):
sev = (match.get("vulnerability", {})
.get("severity", "Unknown")).lower()
counts[sev] += 1
return counts
def print_summary(counts):
total = sum(counts.values())
print(f"[+] Total vulnerabilities: {total}")
for sev in reversed(SEVERITY_ORDER):
if counts.get(sev):
print(f" {sev:>10}: {counts[sev]}")
for sev, n in counts.items():
if sev not in SEVERITY_ORDER:
print(f" {sev:>10}: {n}")
def cosign_attest(image, predicate, attest_type, key, dry_run):
cosign = require("cosign") or "cosign"
cmd = [cosign, "attest", "--predicate", predicate, "--type", attest_type, image]
if key:
cmd[2:2] = ["--key", key] # insert after 'attest'
rc, _ = run(cmd, dry_run)
return rc
def main():
p = argparse.ArgumentParser(description="SBOM generate/scan/attest helper")
p.add_argument("--dry-run", action="store_true")
sub = p.add_subparsers(dest="cmd", required=True)
g = sub.add_parser("generate", help="Generate an SBOM with Syft")
g.add_argument("--source", required=True, help="image, dir:., file:..., etc.")
g.add_argument("--format", default="cyclonedx-json")
g.add_argument("--out", required=True)
s = sub.add_parser("scan", help="Scan an SBOM with Grype")
s.add_argument("--sbom", required=True)
s.add_argument("--out", default="vulns.json")
s.add_argument("--fail-on")
s.add_argument("--only-fixed", action="store_true")
pl = sub.add_parser("pipeline", help="generate -> scan -> summarize (+attest)")
pl.add_argument("--source", required=True)
pl.add_argument("--format", default="cyclonedx-json")
pl.add_argument("--sbom-out", default="sbom.json")
pl.add_argument("--vulns-out", default="vulns.json")
pl.add_argument("--fail-on")
pl.add_argument("--only-fixed", action="store_true")
pl.add_argument("--attest-image", help="If set, attest the SBOM to this image")
pl.add_argument("--attest-type", default="cyclonedx")
pl.add_argument("--cosign-key")
args = p.parse_args()
if args.cmd == "generate":
return syft_generate(args.source, args.format, args.out, args.dry_run)
if args.cmd == "scan":
rc, out = grype_scan(args.sbom, args.out, args.fail_on,
args.only_fixed, args.dry_run)
if out:
print_summary(summarize(out))
return rc
if args.cmd == "pipeline":
rc = syft_generate(args.source, args.format, args.sbom_out, args.dry_run)
if rc not in (0,) and not args.dry_run:
print("[!] SBOM generation failed", file=sys.stderr)
return rc
scan_rc, out = grype_scan(args.sbom_out, args.vulns_out, args.fail_on,
args.only_fixed, args.dry_run)
if out:
print_summary(summarize(out))
if args.attest_image:
cosign_attest(args.attest_image, args.sbom_out, args.attest_type,
args.cosign_key, args.dry_run)
return scan_rc
return 2
if __name__ == "__main__":
sys.exit(main())