mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-29 15:40:58 +03:00
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.
162 lines
6.0 KiB
Python
162 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Trivy scanning helper.
|
|
|
|
Wraps the Trivy CLI to scan container images, filesystems/IaC, and SBOMs,
|
|
parse the JSON results, summarise findings by severity, and exit non-zero
|
|
when findings at or above a chosen threshold are present (CI/CD gating).
|
|
|
|
Requires the `trivy` binary on PATH. See https://github.com/aquasecurity/trivy
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from collections import Counter
|
|
from datetime import datetime, timezone
|
|
|
|
SEVERITY_ORDER = ["LOW", "MEDIUM", "HIGH", "CRITICAL"]
|
|
|
|
|
|
def ensure_trivy() -> str:
|
|
"""Return the trivy executable path or exit with guidance."""
|
|
path = shutil.which("trivy")
|
|
if not path:
|
|
print("[!] trivy not found on PATH. Install: "
|
|
"https://trivy.dev/latest/getting-started/installation/",
|
|
file=sys.stderr)
|
|
sys.exit(2)
|
|
return path
|
|
|
|
|
|
def build_command(trivy: str, args: argparse.Namespace) -> list:
|
|
"""Construct the trivy command line for the requested target."""
|
|
cmd = [trivy, args.target]
|
|
cmd += ["--scanners", args.scanners]
|
|
if args.severity:
|
|
cmd += ["--severity", args.severity]
|
|
if args.ignore_unfixed:
|
|
cmd.append("--ignore-unfixed")
|
|
# Always request JSON so this helper can parse + gate deterministically.
|
|
cmd += ["--format", "json"]
|
|
# exit-code 0 here; gating is enforced in Python after parsing.
|
|
cmd += ["--exit-code", "0"]
|
|
cmd.append(args.subject)
|
|
return cmd
|
|
|
|
|
|
def run_scan(cmd: list, timeout: int) -> dict:
|
|
"""Execute trivy and return the parsed JSON report."""
|
|
try:
|
|
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
|
|
except subprocess.TimeoutExpired:
|
|
print(f"[!] Trivy scan timed out after {timeout}s", file=sys.stderr)
|
|
sys.exit(3)
|
|
if proc.returncode not in (0,):
|
|
# Trivy writes scan results to stdout; real errors go to stderr.
|
|
if not proc.stdout.strip():
|
|
print(f"[!] Trivy failed (rc={proc.returncode}): {proc.stderr.strip()}",
|
|
file=sys.stderr)
|
|
sys.exit(proc.returncode)
|
|
try:
|
|
return json.loads(proc.stdout)
|
|
except json.JSONDecodeError:
|
|
print("[!] Could not parse Trivy JSON output.", file=sys.stderr)
|
|
print(proc.stderr.strip(), file=sys.stderr)
|
|
sys.exit(4)
|
|
|
|
|
|
def summarise(report: dict) -> tuple:
|
|
"""Return (severity Counter, list of finding dicts) from a Trivy report."""
|
|
counts = Counter()
|
|
findings = []
|
|
for result in report.get("Results", []) or []:
|
|
target = result.get("Target", "")
|
|
for vuln in result.get("Vulnerabilities", []) or []:
|
|
sev = (vuln.get("Severity") or "UNKNOWN").upper()
|
|
counts[sev] += 1
|
|
findings.append({
|
|
"type": "vuln",
|
|
"target": target,
|
|
"id": vuln.get("VulnerabilityID"),
|
|
"pkg": vuln.get("PkgName"),
|
|
"installed": vuln.get("InstalledVersion"),
|
|
"fixed": vuln.get("FixedVersion"),
|
|
"severity": sev,
|
|
})
|
|
for mis in result.get("Misconfigurations", []) or []:
|
|
sev = (mis.get("Severity") or "UNKNOWN").upper()
|
|
counts[sev] += 1
|
|
findings.append({
|
|
"type": "misconfig",
|
|
"target": target,
|
|
"id": mis.get("ID"),
|
|
"title": mis.get("Title"),
|
|
"severity": sev,
|
|
})
|
|
for sec in result.get("Secrets", []) or []:
|
|
sev = (sec.get("Severity") or "UNKNOWN").upper()
|
|
counts[sev] += 1
|
|
findings.append({
|
|
"type": "secret",
|
|
"target": target,
|
|
"id": sec.get("RuleID"),
|
|
"title": sec.get("Title"),
|
|
"severity": sev,
|
|
})
|
|
return counts, findings
|
|
|
|
|
|
def gate(counts: Counter, threshold: str) -> bool:
|
|
"""Return True if any finding is at or above threshold severity."""
|
|
if threshold not in SEVERITY_ORDER:
|
|
return False
|
|
idx = SEVERITY_ORDER.index(threshold)
|
|
blocking = SEVERITY_ORDER[idx:]
|
|
return any(counts.get(s, 0) > 0 for s in blocking)
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="Trivy scan + CI/CD gate helper")
|
|
parser.add_argument("subject", help="Image ref, directory, repo URL, or SBOM file")
|
|
parser.add_argument("--target", default="image",
|
|
choices=["image", "fs", "config", "repo", "sbom"],
|
|
help="Trivy scan target subcommand")
|
|
parser.add_argument("--scanners", default="vuln",
|
|
help="Comma list: vuln,misconfig,secret,license")
|
|
parser.add_argument("--severity", default="HIGH,CRITICAL",
|
|
help="Severities to include")
|
|
parser.add_argument("--ignore-unfixed", action="store_true",
|
|
help="Skip vulns with no fix available")
|
|
parser.add_argument("--gate", default="", choices=["", *SEVERITY_ORDER],
|
|
help="Exit non-zero if findings >= this severity")
|
|
parser.add_argument("--timeout", type=int, default=600, help="Scan timeout (s)")
|
|
parser.add_argument("--output", help="Write JSON summary to file")
|
|
args = parser.parse_args()
|
|
|
|
trivy = ensure_trivy()
|
|
cmd = build_command(trivy, args)
|
|
print(f"[*] {datetime.now(timezone.utc).isoformat()} running: {' '.join(cmd)}")
|
|
report = run_scan(cmd, args.timeout)
|
|
counts, findings = summarise(report)
|
|
|
|
print("\n=== TRIVY FINDINGS BY SEVERITY ===")
|
|
for sev in reversed(SEVERITY_ORDER):
|
|
print(f" {sev:<9}: {counts.get(sev, 0)}")
|
|
print(f" TOTAL : {sum(counts.values())}")
|
|
|
|
if args.output:
|
|
with open(args.output, "w", encoding="utf-8") as fh:
|
|
json.dump({"counts": dict(counts), "findings": findings}, fh, indent=2)
|
|
print(f"[+] Summary written to {args.output}")
|
|
|
|
if args.gate and gate(counts, args.gate):
|
|
print(f"[!] GATE FAILED: findings at or above {args.gate}", file=sys.stderr)
|
|
sys.exit(1)
|
|
print("[+] Scan complete.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|