mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-30 16:06:52 +03:00
Add 55 new skills across 3 new domains + 6 undercovered areas (762 -> 817)
Demand-driven expansion targeting the fastest-growing 2025-2026 threat and
skills categories (ISC2/WEF/CrowdStrike/Mandiant signals):
- AI Security (NEW domain, 12 skills): LLM red-teaming with garak/PyRIT,
prompt injection (direct/indirect/RAG), MCP tool-poisoning, agentic tool
invocation, guardrails, model/data poisoning, system-prompt leakage,
embedding/vector weaknesses, model extraction, continuous red-teaming
- Supply Chain Security (NEW domain, 5 skills): SBOMs, dependency confusion,
malicious-npm triage, typosquatting, SLSA/Sigstore provenance
- Hardware & Firmware Security (NEW domain, 4 skills): CHIPSEC/UEFI audit,
Secure Boot bypass, TPM measured-boot attestation, ESP bootkit hunting
- Identity (10): Entra ID/ROADtools, GraphRunner, AADInternals, ADCS/Certipy,
shadow credentials, coercion, BloodHound CE, device-code phishing, SSO abuse
- Cloud-native (8): Stratus, Pacu, CloudFox, container escape, K8s RBAC,
Falco, Trivy, kube-bench
- Offensive C2 (6): Sliver, Havoc, NetExec, DPAPI, NTLM relay ESC8, redirectors
- DFIR (6): Hayabusa, Chainsaw, KAPE, Velociraptor, EZ Tools, Plaso
- Backfill (4): OpenCTI, MISP, honeytokens, post-quantum crypto migration
Each skill follows the repo taxonomy (SKILL.md + references/{standards,api-reference}.md
+ scripts/agent.py + LICENSE), with researched real tool commands (no placeholders),
complete frontmatter, and ATT&CK/ATLAS + NIST CSF mappings. Updates README domain
table, skill count, and index.json.
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
#!/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())
|
||||
Reference in New Issue
Block a user