reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
# Skill Validation Tools
## validate-skill.py
Validate SKILL.md metadata before submitting a PR.
### Usage
```bash
# Validate a single skill
python tools/validate-skill.py skills/my-new-skill/
# Validate all skills
python tools/validate-skill.py --all
```
### What it checks
- SKILL.md exists in the skill directory
- Valid YAML frontmatter (between `---` markers)
- Required fields present: `name`, `description`, `domain`, `subdomain`, `tags`, `version`, `author`, `license`
- Name is kebab-case, 1–64 characters
- Description is at least 50 characters (agentskills.io caps it at 1024; `tools/validate-agentskills.py` enforces that)
- Domain is `cybersecurity`
- Subdomain is from the allowed list
- Tags is a list with at least 2 items
### Requirements
Python 3.8+ and PyYAML (`pip install pyyaml`).
All frontmatter is parsed by `skill_frontmatter.py`, the single PyYAML-backed loader. It replaced three hand-rolled regex parsers that silently truncated multi-line descriptions to their first line — that bug shipped 604 of 817 descriptions broken in `index.json`. Do not reintroduce regex frontmatter parsing; CI fails the build if it detects any.

View File

@@ -0,0 +1,46 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://agentskills.io/schema/skill-frontmatter.json",
"title": "agentskills.io SKILL.md frontmatter",
"description": "JSON Schema for the YAML frontmatter of a SKILL.md file per the agentskills.io open standard (Anthropic, 2025-12-18). Only `name` and `description` are required; `license`, `compatibility`, `metadata`, and `allowed-tools` are recognized optional fields. Additional top-level keys are PERMITTED as extra metadata (this repo uses domain/subdomain/tags/version/author and framework-mapping keys), so `additionalProperties` is true. Constraints JSON Schema cannot express (name must equal the parent directory; no angle-bracket content in frontmatter) are enforced by tools/validate-agentskills.py.",
"type": "object",
"additionalProperties": true,
"required": ["name", "description"],
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
"description": "1-64 chars, lowercase alphanumeric and single hyphens only; no leading/trailing/consecutive hyphens; must match the parent directory name; must not be a reserved word."
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 1024,
"description": "1-1024 chars. Must state BOTH what the skill does and when to use it."
},
"license": {
"type": "string",
"minLength": 1,
"description": "SPDX license identifier or license text."
},
"compatibility": {
"type": "string",
"maxLength": 500,
"description": "Free-text compatibility notes (<=500 chars)."
},
"metadata": {
"type": "object",
"description": "Arbitrary key/value map for non-standard fields. This is where domain, subdomain, tags, version, author, and framework mappings (mitre_attack, nist_csf, atlas_techniques, d3fend_techniques, nist_ai_rmf, mitre_f3) belong under strict compliance.",
"additionalProperties": true
},
"allowed-tools": {
"description": "EXPERIMENTAL. Tools the skill is permitted to use; string or array of strings.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
}
}
}

View File

@@ -0,0 +1,25 @@
{
"_comment": [
"Skill pairs that score as near-duplicates but are legitimately distinct.",
"",
"Add a pair here ONLY after reading both descriptions and confirming a real",
"difference in scope, platform, or offense-vs-defense posture. The 'reason'",
"is not bookkeeping: it is the wording each skill's negative trigger should",
"use, e.g. reason 'Linux vs Windows' becomes 'Do not use for Windows hosts",
"- use hardening-windows-endpoint-with-cis-benchmark.'",
"",
"A pair that is genuinely ambiguous does NOT belong here. Disambiguate the",
"two descriptions instead.",
"",
"Regenerate the candidate list with: python tools/detect-collisions.py"
],
"reviewed_distinct": [
{
"pair": [
"hardening-linux-endpoint-with-cis-benchmark",
"hardening-windows-endpoint-with-cis-benchmark"
],
"reason": "Same CIS Benchmark methodology, different operating systems. The controls, tooling and audit commands do not overlap, so both must exist; each description must name the OS explicitly and point at the other."
}
]
}

View File

@@ -0,0 +1,186 @@
#!/usr/bin/env python3
"""Find skill pairs whose descriptions compete for the same user request.
An agent picks a skill from its description alone. When two descriptions are
near-duplicates, the router cannot reliably choose between them and misroutes
-- "skill collision". This scores every pair by TF-IDF cosine similarity over
description + slug and reports the ones close enough to collide.
A high score is NOT automatically a defect. Some near-twins are legitimately
distinct (Linux vs Windows CIS hardening; red-team DCSync vs blue-team DCSync
detection). Those belong in tools/collision-allowlist.json with a reason, which
is also a record of WHY they differ -- exactly the wording their negative
triggers need.
Pure stdlib; no numpy/sklearn required.
Usage:
python tools/detect-collisions.py
python tools/detect-collisions.py --threshold 0.5
python tools/detect-collisions.py --json
python tools/detect-collisions.py --max-unreviewed 60 # CI gate
"""
from __future__ import annotations
import argparse
import itertools
import json
import math
import os
import re
import sys
from collections import Counter
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from skill_frontmatter import description_of, iter_skill_dirs, load_frontmatter, FrontmatterError
ALLOWLIST_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)),
"collision-allowlist.json")
DEFAULT_THRESHOLD = 0.45
# Words too common in this corpus to carry signal.
STOPWORDS = set("""
the a an and or of to for in on with using use uses used when this that is are be by
from as it its into via at not skill security detect detects detecting analyze analyzes
analyzing perform performs performing implement implements implementing
""".split())
# A term appearing in more than this many skills is treated as a domain-wide
# background word and skipped when pairing (keeps the comparison O(usable pairs)).
MAX_DOCS_PER_TERM = 60
# A negative trigger names the sibling skill on purpose ("Do not use for X -
# use other-skill."). Scoring that text would inject the sibling's own slug
# tokens into this skill's vector, so correctly disambiguating a pair would
# RAISE its similarity score -- the metric would punish the fix. Strip the
# disambiguation scaffolding and score only the descriptive part.
DISAMBIGUATION_RE = re.compile(r"\b(?:do\s+not\s+use|don'?t\s+use|avoid\s+(?:this\s+)?(?:skill\s+)?for)\b.*",
re.IGNORECASE | re.DOTALL)
KEYWORDS_LABEL_RE = re.compile(r"\bkeywords\s*:", re.IGNORECASE)
def strip_disambiguation(text: str) -> str:
"""Drop negative-trigger sentences and the literal 'Keywords:' label.
The keyword TERMS stay -- they are real content. Only the label is removed,
since it would otherwise be a shared token across every fixed skill.
"""
text = DISAMBIGUATION_RE.sub("", text)
return KEYWORDS_LABEL_RE.sub(" ", text)
def tokenize(text: str) -> Counter:
return Counter(w for w in re.findall(r"[a-z0-9]+", text.lower())
if w not in STOPWORDS and len(w) > 2)
def build_vectors(skills_dir: str) -> dict[str, dict[str, float]]:
"""L2-normalized TF-IDF vectors keyed by slug."""
docs: dict[str, Counter] = {}
for slug, skill_dir in iter_skill_dirs(skills_dir):
try:
frontmatter = load_frontmatter(os.path.join(skill_dir, "SKILL.md"))
except FrontmatterError:
continue
described = strip_disambiguation(description_of(frontmatter))
docs[slug] = tokenize(f"{described} {slug.replace('-', ' ')}")
doc_freq: Counter = Counter()
for counts in docs.values():
doc_freq.update(counts.keys())
total = len(docs)
vectors: dict[str, dict[str, float]] = {}
for slug, counts in docs.items():
weights = {term: (1 + math.log(freq)) * math.log(total / doc_freq[term])
for term, freq in counts.items()}
norm = math.sqrt(sum(w * w for w in weights.values())) or 1.0
vectors[slug] = {term: w / norm for term, w in weights.items()}
return vectors
def score_pairs(vectors: dict[str, dict[str, float]], threshold: float):
"""Cosine similarity for every pair sharing at least one discriminating term."""
postings: dict[str, list[str]] = {}
for slug, vector in vectors.items():
for term in vector:
postings.setdefault(term, []).append(slug)
sims: dict[tuple[str, str], float] = {}
for term, slugs in postings.items():
if len(slugs) > MAX_DOCS_PER_TERM:
continue
weight_by_slug = {s: vectors[s][term] for s in slugs}
for a, b in itertools.combinations(sorted(slugs), 2):
sims[(a, b)] = sims.get((a, b), 0.0) + weight_by_slug[a] * weight_by_slug[b]
return sorted(((s, p) for p, s in sims.items() if s >= threshold), reverse=True)
def load_allowlist() -> dict[tuple[str, str], str]:
if not os.path.isfile(ALLOWLIST_PATH):
return {}
with open(ALLOWLIST_PATH, encoding="utf-8") as handle:
data = json.load(handle)
out: dict[tuple[str, str], str] = {}
for entry in data.get("reviewed_distinct", []):
pair = tuple(sorted(entry["pair"]))
out[pair] = entry.get("reason", "")
return out
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--threshold", type=float, default=DEFAULT_THRESHOLD)
parser.add_argument("--json", action="store_true", dest="as_json")
parser.add_argument("--max-unreviewed", type=int, default=None,
help="exit 1 if unreviewed colliding pairs exceed this")
parser.add_argument("--skills-dir", default="skills")
args = parser.parse_args()
if not os.path.isdir(args.skills_dir):
print(f"ERROR: '{args.skills_dir}' not found. Run from the repository root.")
return 1
vectors = build_vectors(args.skills_dir)
pairs = score_pairs(vectors, args.threshold)
allowlist = load_allowlist()
unreviewed = [(s, p) for s, p in pairs if p not in allowlist]
reviewed = [(s, p) for s, p in pairs if p in allowlist]
involved = {slug for _, pair in unreviewed for slug in pair}
if args.as_json:
print(json.dumps({
"threshold": args.threshold,
"total_pairs": len(pairs),
"unreviewed": [{"score": round(s, 3), "pair": list(p)} for s, p in unreviewed],
"reviewed_distinct": [{"score": round(s, 3), "pair": list(p),
"reason": allowlist[p]} for s, p in reviewed],
"skills_involved": sorted(involved),
}, indent=2))
else:
print(f"Colliding pairs at cosine >= {args.threshold}: {len(pairs)} "
f"({len(reviewed)} reviewed-distinct, {len(unreviewed)} unreviewed)")
print(f"Skills involved in an unreviewed collision: {len(involved)} "
f"of {len(vectors)}\n")
for score, (a, b) in unreviewed:
print(f" {score:.2f} {a}\n {b}")
if reviewed:
print(f"\nReviewed as legitimately distinct ({len(reviewed)}):")
for score, (a, b) in reviewed:
print(f" {score:.2f} {a} || {b}\n reason: {allowlist[(a, b)]}")
if args.max_unreviewed is not None and len(unreviewed) > args.max_unreviewed:
print(f"\nERROR: {len(unreviewed)} unreviewed colliding pairs "
f"exceeds --max-unreviewed {args.max_unreviewed}.")
print("Either disambiguate the descriptions or record the pair in "
f"{os.path.relpath(ALLOWLIST_PATH)} with a reason.")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env python3
"""Generate index.json from the SKILL.md files under skills/.
Previously this logic lived as an inline heredoc inside
.github/workflows/update-index.yml with a hand-rolled regex YAML parser that
truncated 604 of 817 descriptions. It lives here now so it is testable outside
CI and shares one PyYAML-backed parser with every other tool.
Usage:
python tools/generate-index.py # write index.json
python tools/generate-index.py --check # verify index.json is current (CI)
"""
from __future__ import annotations
import argparse
import json
import os
import sys
from datetime import datetime, timezone
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from skill_frontmatter import description_of, iter_skill_dirs, load_frontmatter, FrontmatterError
INDEX_VERSION = "1.1.0"
REPOSITORY = "https://github.com/mukul975/Anthropic-Cybersecurity-Skills"
DEFAULT_DOMAIN = "cybersecurity"
def build_index(skills_dir: str = "skills") -> tuple[dict, list[str]]:
"""Build the index payload. Returns (index, errors)."""
skills = []
errors = []
for slug, skill_dir in iter_skill_dirs(skills_dir):
try:
frontmatter = load_frontmatter(os.path.join(skill_dir, "SKILL.md"))
except FrontmatterError as exc:
errors.append(f"{slug}: {exc}")
continue
description = description_of(frontmatter)
if not description:
errors.append(f"{slug}: empty description")
skills.append({
"name": slug,
"description": description,
"domain": frontmatter.get("domain") or DEFAULT_DOMAIN,
"path": f"{skills_dir}/{slug}",
})
index = {
"version": INDEX_VERSION,
"generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"repository": REPOSITORY,
"domain": DEFAULT_DOMAIN,
"total_skills": len(skills),
"skills": skills,
}
return index, errors
def _comparable(index: dict) -> str:
"""Serialize an index ignoring generated_at, so --check tolerates a re-run."""
return json.dumps({k: v for k, v in index.items() if k != "generated_at"}, sort_keys=True)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--check", action="store_true",
help="verify index.json matches the skills tree; do not write")
parser.add_argument("--skills-dir", default="skills")
parser.add_argument("--out", default="index.json")
args = parser.parse_args()
if not os.path.isdir(args.skills_dir):
print(f"ERROR: '{args.skills_dir}' not found. Run from the repository root.")
return 1
index, errors = build_index(args.skills_dir)
for error in errors:
print(f"ERROR {error}")
if errors:
print(f"\n{len(errors)} skill(s) could not be indexed.")
return 1
if args.check:
if not os.path.isfile(args.out):
print(f"ERROR: {args.out} is missing. Run: python tools/generate-index.py")
return 1
with open(args.out, encoding="utf-8") as handle:
current = json.load(handle)
if _comparable(current) != _comparable(index):
print(f"ERROR: {args.out} is out of date. Run: python tools/generate-index.py")
return 1
print(f"OK: {args.out} is up to date ({index['total_skills']} skills)")
return 0
with open(args.out, "w", encoding="utf-8") as handle:
json.dump(index, handle, separators=(",", ":"))
print(f"Updated {args.out}: {index['total_skills']} skills")
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,992 @@
{
"_comment": "Pre-existing lint failures, grandfathered so CI can gate new work today. This file may only shrink. Never add a slug by hand -- fix the skill, then run: python tools/lint-descriptions.py --update-baseline",
"_total_grandfathered": 980,
"desc-ends-punctuation": [
"analyzing-active-directory-acl-abuse",
"analyzing-malicious-url-with-urlscan",
"detecting-aws-iam-privilege-escalation",
"exploiting-active-directory-with-bloodhound",
"implementing-email-sandboxing-with-proofpoint",
"implementing-patch-management-workflow",
"implementing-secrets-scanning-in-ci-cd",
"performing-cryptographic-audit-of-application",
"performing-dark-web-monitoring-for-threats",
"performing-malware-ioc-extraction",
"performing-open-source-intelligence-gathering",
"performing-service-account-audit",
"prioritizing-vulnerabilities-with-cvss-scoring"
],
"desc-has-use-when": [
"analyzing-active-directory-acl-abuse",
"analyzing-android-malware-with-apktool",
"analyzing-apt-group-with-mitre-navigator",
"analyzing-certificate-transparency-for-phishing",
"analyzing-cobalt-strike-beacon-configuration",
"analyzing-docker-container-forensics",
"analyzing-ethereum-smart-contract-vulnerabilities",
"analyzing-heap-spray-exploitation",
"analyzing-ios-app-security-with-objection",
"analyzing-linux-audit-logs-for-intrusion",
"analyzing-linux-kernel-rootkits",
"analyzing-macro-malware-in-office-documents",
"analyzing-malicious-url-with-urlscan",
"analyzing-memory-dumps-with-volatility",
"analyzing-network-flow-data-with-netflow",
"analyzing-network-traffic-for-incidents",
"analyzing-network-traffic-of-malware",
"analyzing-network-traffic-with-wireshark",
"analyzing-office365-audit-logs-for-compromise",
"analyzing-pdf-malware-with-pdfid",
"analyzing-powershell-script-block-logging",
"analyzing-ransomware-encryption-mechanisms",
"analyzing-sbom-for-supply-chain-vulnerabilities",
"analyzing-security-logs-with-splunk",
"analyzing-supply-chain-malware-artifacts",
"analyzing-web-server-logs-for-intrusion",
"auditing-aws-s3-bucket-permissions",
"auditing-azure-active-directory-configuration",
"auditing-gcp-iam-permissions",
"auditing-kubernetes-cluster-rbac",
"auditing-terraform-infrastructure-for-security",
"auditing-tls-certificate-transparency-logs",
"auditing-uefi-firmware-with-chipsec",
"building-detection-rule-with-splunk-spl",
"bypassing-authentication-with-forced-browsing",
"coercing-authentication-with-coercer-petitpotam",
"collecting-indicators-of-compromise",
"conducting-api-security-testing",
"conducting-cloud-penetration-testing",
"conducting-domain-persistence-with-dcsync",
"conducting-internal-network-penetration-test",
"conducting-man-in-the-middle-attack-simulation",
"conducting-memory-forensics-with-volatility",
"conducting-mobile-app-penetration-test",
"conducting-network-penetration-test",
"conducting-post-incident-lessons-learned",
"conducting-social-engineering-pretext-call",
"conducting-spearphishing-simulation-campaign",
"conducting-wireless-network-penetration-test",
"containing-active-breach",
"deploying-decoy-files-for-ransomware-detection",
"detecting-anomalous-authentication-patterns",
"detecting-attacks-on-scada-systems",
"detecting-aws-cloudtrail-anomalies",
"detecting-aws-iam-privilege-escalation",
"detecting-azure-lateral-movement",
"detecting-business-email-compromise-with-ai",
"detecting-cryptomining-in-cloud",
"detecting-lateral-movement-in-network",
"detecting-lateral-movement-with-zeek",
"detecting-living-off-the-land-attacks",
"detecting-malicious-scheduled-tasks-with-sysmon",
"detecting-network-scanning-with-ids-signatures",
"detecting-port-scanning-with-fail2ban",
"detecting-process-injection-techniques",
"detecting-ransomware-precursors-in-network",
"detecting-s3-data-exfiltration-attempts",
"detecting-serverless-function-injection",
"detecting-sql-injection-via-waf-logs",
"detecting-suspicious-oauth-application-consent",
"detecting-typosquatting-packages-in-npm-pypi",
"emulating-cloud-attacks-with-stratus-red-team",
"enumerating-cloud-with-cloudfox",
"executing-active-directory-attack-simulation",
"executing-phishing-simulation-campaign",
"exploiting-active-directory-certificate-services-esc1",
"exploiting-active-directory-with-bloodhound",
"exploiting-bgp-hijacking-vulnerabilities",
"exploiting-insecure-deserialization",
"exploiting-ipv6-vulnerabilities",
"exploiting-oauth-misconfiguration",
"exploiting-server-side-request-forgery",
"exploiting-smb-vulnerabilities-with-metasploit",
"exploiting-sql-injection-vulnerabilities",
"exploiting-sql-injection-with-sqlmap",
"exploiting-websocket-vulnerabilities",
"extracting-windows-event-logs-artifacts",
"hunting-for-anomalous-powershell-execution",
"hunting-for-beaconing-with-frequency-analysis",
"hunting-for-command-and-control-beaconing",
"hunting-for-defense-evasion-via-timestomping",
"hunting-for-registry-run-key-persistence",
"hunting-for-spearphishing-indicators",
"implementing-aqua-security-for-container-scanning",
"implementing-cloud-trail-log-analysis",
"implementing-ddos-mitigation-with-cloudflare",
"implementing-diamond-model-analysis",
"implementing-email-sandboxing-with-proofpoint",
"implementing-honeypot-for-ransomware-detection",
"implementing-mitre-attack-coverage-mapping",
"implementing-network-deception-with-honeypots",
"implementing-patch-management-workflow",
"implementing-proofpoint-email-security-gateway",
"implementing-runtime-application-self-protection",
"implementing-secret-scanning-with-gitleaks",
"implementing-secrets-scanning-in-ci-cd",
"implementing-security-monitoring-with-datadog",
"implementing-semgrep-for-custom-sast-rules",
"implementing-velociraptor-for-ir-collection",
"investigating-ransomware-attack-artifacts",
"monitoring-scada-modbus-traffic-anomalies",
"performing-active-directory-compromise-investigation",
"performing-active-directory-vulnerability-assessment",
"performing-agentless-vulnerability-scanning",
"performing-api-inventory-and-discovery",
"performing-aws-privilege-escalation-assessment",
"performing-brand-monitoring-for-impersonation",
"performing-clickjacking-attack-test",
"performing-credential-access-with-lazagne",
"performing-cryptographic-audit-of-application",
"performing-csrf-attack-simulation",
"performing-dark-web-monitoring-for-threats",
"performing-dns-enumeration-and-zone-transfer",
"performing-external-network-penetration-test",
"performing-firmware-extraction-with-binwalk",
"performing-gcp-security-assessment-with-forseti",
"performing-graphql-depth-limit-attack",
"performing-graphql-security-assessment",
"performing-initial-access-with-evilginx3",
"performing-iot-security-assessment",
"performing-ip-reputation-analysis-with-shodan",
"performing-lateral-movement-with-wmiexec",
"performing-log-analysis-for-forensic-investigation",
"performing-malware-ioc-extraction",
"performing-malware-persistence-investigation",
"performing-memory-forensics-with-volatility3-plugins",
"performing-mobile-app-certificate-pinning-bypass",
"performing-oauth-scope-minimization-review",
"performing-open-source-intelligence-gathering",
"performing-ot-network-security-assessment",
"performing-ot-vulnerability-scanning-safely",
"performing-packet-injection-attack",
"performing-paste-site-monitoring-for-credentials",
"performing-physical-intrusion-assessment",
"performing-plc-firmware-security-analysis",
"performing-privilege-escalation-assessment",
"performing-s7comm-protocol-security-analysis",
"performing-sca-dependency-scanning-with-snyk",
"performing-scada-hmi-security-assessment",
"performing-second-order-sql-injection",
"performing-security-headers-audit",
"performing-serverless-function-security-review",
"performing-service-account-audit",
"performing-subdomain-enumeration-with-subfinder",
"performing-thick-client-application-penetration-test",
"performing-threat-hunting-with-yara-rules",
"performing-vulnerability-scanning-with-nessus",
"performing-web-application-penetration-test",
"performing-web-cache-poisoning-attack",
"performing-wifi-password-cracking-with-aircrack",
"performing-wireless-network-penetration-test",
"performing-wireless-security-assessment-with-kismet",
"prioritizing-vulnerabilities-with-cvss-scoring",
"reverse-engineering-ransomware-encryption-routine",
"scanning-infrastructure-with-nessus",
"testing-api-authentication-weaknesses",
"testing-cors-misconfiguration",
"testing-for-host-header-injection",
"testing-for-sensitive-data-exposure",
"testing-for-xml-injection-vulnerabilities",
"testing-for-xss-vulnerabilities-with-burpsuite",
"testing-for-xxe-injection-vulnerabilities",
"testing-jwt-token-security",
"validating-tpm-measured-boot-attestation",
"verifying-build-provenance-with-slsa-sigstore"
],
"desc-has-negative-trigger": [
"abusing-dpapi-for-credential-access",
"abusing-shadow-credentials-for-privesc",
"achieving-cmmc-level-2-compliance",
"acquiring-disk-image-with-dd-and-dcfldd",
"analyzing-active-directory-acl-abuse",
"analyzing-android-malware-with-apktool",
"analyzing-api-gateway-access-logs",
"analyzing-apt-group-with-mitre-navigator",
"analyzing-azure-activity-logs-for-threats",
"analyzing-bootkit-and-rootkit-samples",
"analyzing-browser-forensics-with-hindsight",
"analyzing-campaign-attribution-evidence",
"analyzing-certificate-transparency-for-phishing",
"analyzing-cloud-storage-access-patterns",
"analyzing-cobalt-strike-beacon-configuration",
"analyzing-cobaltstrike-malleable-c2-profiles",
"analyzing-command-and-control-communication",
"analyzing-cyber-kill-chain",
"analyzing-disk-image-with-autopsy",
"analyzing-dns-logs-for-exfiltration",
"analyzing-docker-container-forensics",
"analyzing-email-headers-for-phishing-investigation",
"analyzing-ethereum-smart-contract-vulnerabilities",
"analyzing-golang-malware-with-ghidra",
"analyzing-heap-spray-exploitation",
"analyzing-indicators-of-compromise",
"analyzing-ios-app-security-with-objection",
"analyzing-linux-audit-logs-for-intrusion",
"analyzing-linux-elf-malware",
"analyzing-linux-kernel-rootkits",
"analyzing-linux-system-artifacts",
"analyzing-lnk-file-and-jump-list-artifacts",
"analyzing-macro-malware-in-office-documents",
"analyzing-malicious-pdf-with-peepdf",
"analyzing-malicious-url-with-urlscan",
"analyzing-malware-behavior-with-cuckoo-sandbox",
"analyzing-malware-family-relationships-with-malpedia",
"analyzing-malware-persistence-with-autoruns",
"analyzing-malware-sandbox-evasion-techniques",
"analyzing-memory-dumps-with-volatility",
"analyzing-memory-forensics-with-lime-and-volatility",
"analyzing-mft-for-deleted-file-recovery",
"analyzing-network-covert-channels-in-malware",
"analyzing-network-flow-data-with-netflow",
"analyzing-network-packets-with-scapy",
"analyzing-network-traffic-for-incidents",
"analyzing-network-traffic-of-malware",
"analyzing-network-traffic-with-wireshark",
"analyzing-office365-audit-logs-for-compromise",
"analyzing-outlook-pst-for-email-forensics",
"analyzing-packed-malware-with-upx-unpacker",
"analyzing-pdf-malware-with-pdfid",
"analyzing-persistence-mechanisms-in-linux",
"analyzing-powershell-empire-artifacts",
"analyzing-powershell-script-block-logging",
"analyzing-prefetch-files-for-execution-history",
"analyzing-ransomware-encryption-mechanisms",
"analyzing-ransomware-leak-site-intelligence",
"analyzing-ransomware-network-indicators",
"analyzing-ransomware-payment-wallets",
"analyzing-sbom-for-supply-chain-vulnerabilities",
"analyzing-security-logs-with-splunk",
"analyzing-slack-space-and-file-system-artifacts",
"analyzing-supply-chain-malware-artifacts",
"analyzing-threat-actor-ttps-with-mitre-attack",
"analyzing-threat-actor-ttps-with-mitre-navigator",
"analyzing-threat-intelligence-feeds",
"analyzing-threat-landscape-with-misp",
"analyzing-tls-certificate-transparency-logs",
"analyzing-typosquatting-domains-with-dnstwist",
"analyzing-uefi-bootkit-persistence",
"analyzing-usb-device-connection-history",
"analyzing-web-server-logs-for-intrusion",
"analyzing-windows-amcache-artifacts",
"analyzing-windows-event-logs-in-splunk",
"analyzing-windows-lnk-files-for-artifacts",
"analyzing-windows-prefetch-with-python",
"analyzing-windows-registry-for-artifacts",
"analyzing-windows-shellbag-artifacts",
"assessing-vector-and-embedding-weaknesses",
"attacking-entra-id-with-roadtools",
"attacking-oauth-with-device-code-phishing",
"auditing-aws-s3-bucket-permissions",
"auditing-azure-active-directory-configuration",
"auditing-cloud-with-cis-benchmarks",
"auditing-entra-id-with-aadinternals",
"auditing-foundry-smart-contract-security",
"auditing-gcp-iam-permissions",
"auditing-kubernetes-cluster-rbac",
"auditing-mcp-servers-for-tool-poisoning",
"auditing-terraform-infrastructure-for-security",
"auditing-tls-certificate-transparency-logs",
"auditing-uefi-firmware-with-chipsec",
"automating-ioc-enrichment",
"building-adversary-infrastructure-tracking-system",
"building-attack-pattern-library-from-cti-reports",
"building-automated-malware-submission-pipeline",
"building-c2-infrastructure-with-sliver-framework",
"building-c2-redirector-infrastructure",
"building-detection-rule-with-splunk-spl",
"building-detection-rules-with-sigma",
"building-devsecops-pipeline-with-gitlab-ci",
"building-identity-federation-with-saml-azure-ad",
"building-identity-governance-lifecycle-process",
"building-incident-response-dashboard",
"building-incident-response-playbook",
"building-incident-timeline-with-timesketch",
"building-ioc-defanging-and-sharing-pipeline",
"building-ioc-enrichment-pipeline-with-opencti",
"building-malware-incident-communication-template",
"building-patch-tuesday-response-process",
"building-phishing-reporting-button-workflow",
"building-ransomware-playbook-with-cisa-framework",
"building-red-team-c2-infrastructure-with-havoc",
"building-role-mining-for-rbac-optimization",
"building-soc-escalation-matrix",
"building-soc-metrics-and-kpi-tracking",
"building-soc-playbook-for-ransomware",
"building-super-timelines-with-plaso",
"building-threat-actor-profile-from-osint",
"building-threat-feed-aggregation-with-misp",
"building-threat-hunt-hypothesis-framework",
"building-threat-intelligence-enrichment-in-splunk",
"building-threat-intelligence-feed-integration",
"building-threat-intelligence-platform",
"building-vulnerability-aging-and-sla-tracking",
"building-vulnerability-dashboard-with-defectdojo",
"building-vulnerability-exception-tracking-system",
"building-vulnerability-scanning-workflow",
"bypassing-authentication-with-forced-browsing",
"coercing-authentication-with-coercer-petitpotam",
"collecting-indicators-of-compromise",
"collecting-open-source-intelligence",
"collecting-threat-intelligence-with-misp",
"collecting-volatile-evidence-from-compromised-host",
"conducting-api-security-testing",
"conducting-cloud-incident-response",
"conducting-cloud-penetration-testing",
"conducting-cyber-risk-assessment-with-nist-800-30",
"conducting-domain-persistence-with-dcsync",
"conducting-external-reconnaissance-with-osint",
"conducting-full-scope-red-team-engagement",
"conducting-internal-network-penetration-test",
"conducting-internal-reconnaissance-with-bloodhound-ce",
"conducting-malware-incident-response",
"conducting-man-in-the-middle-attack-simulation",
"conducting-memory-forensics-with-volatility",
"conducting-mobile-app-penetration-test",
"conducting-network-penetration-test",
"conducting-pass-the-ticket-attack",
"conducting-phishing-incident-response",
"conducting-post-incident-lessons-learned",
"conducting-social-engineering-penetration-test",
"conducting-social-engineering-pretext-call",
"conducting-spearphishing-simulation-campaign",
"conducting-wireless-network-penetration-test",
"configuring-active-directory-tiered-model",
"configuring-aws-verified-access-for-ztna",
"configuring-certificate-authority-with-openssl",
"configuring-host-based-intrusion-detection",
"configuring-hsm-for-key-storage",
"configuring-identity-aware-proxy-with-google-iap",
"configuring-ldap-security-hardening",
"configuring-microsegmentation-for-zero-trust",
"configuring-multi-factor-authentication-with-duo",
"configuring-network-segmentation-with-vlans",
"configuring-oauth2-authorization-flow",
"configuring-pfsense-firewall-rules",
"configuring-snort-ids-for-intrusion-detection",
"configuring-suricata-for-network-monitoring",
"configuring-tls-1-3-for-secure-communications",
"configuring-windows-defender-advanced-settings",
"configuring-windows-event-logging-for-detection",
"configuring-zscaler-private-access-for-ztna",
"containing-active-breach",
"continuous-llm-red-teaming-with-promptfoo",
"correlating-security-events-in-qradar",
"correlating-threat-campaigns",
"defending-llms-with-guardrails",
"deobfuscating-javascript-malware",
"deobfuscating-powershell-obfuscated-malware",
"deploying-active-directory-honeytokens",
"deploying-cloud-deception-with-decoy-resources",
"deploying-cloudflare-access-for-zero-trust",
"deploying-decoy-files-for-ransomware-detection",
"deploying-edr-agent-with-crowdstrike",
"deploying-honeytokens-and-canarytokens",
"deploying-osquery-for-endpoint-monitoring",
"deploying-palo-alto-prisma-access-zero-trust",
"deploying-ransomware-canary-files",
"deploying-software-defined-perimeter",
"deploying-tailscale-for-zero-trust-vpn",
"designing-adversary-engagement-with-mitre-engage",
"detecting-ai-model-prompt-injection-attacks",
"detecting-anomalies-in-industrial-control-systems",
"detecting-anomalous-authentication-patterns",
"detecting-api-enumeration-attacks",
"detecting-arp-poisoning-in-network-traffic",
"detecting-attacks-on-historian-servers",
"detecting-attacks-on-scada-systems",
"detecting-aws-cloudtrail-anomalies",
"detecting-aws-credential-exposure-with-trufflehog",
"detecting-aws-guardduty-findings-automation",
"detecting-aws-iam-privilege-escalation",
"detecting-azure-lateral-movement",
"detecting-azure-service-principal-abuse",
"detecting-azure-storage-account-misconfigurations",
"detecting-beaconing-patterns-with-zeek",
"detecting-bluetooth-low-energy-attacks",
"detecting-broken-object-property-level-authorization",
"detecting-business-email-compromise",
"detecting-business-email-compromise-with-ai",
"detecting-cloud-threats-with-guardduty",
"detecting-command-and-control-over-dns",
"detecting-compromised-cloud-credentials",
"detecting-credential-dumping-techniques",
"detecting-cryptomining-in-cloud",
"detecting-data-and-model-poisoning",
"detecting-dcsync-attack-in-active-directory",
"detecting-deepfake-audio-in-vishing-attacks",
"detecting-dependency-confusion",
"detecting-dll-sideloading-attacks",
"detecting-dnp3-protocol-anomalies",
"detecting-dns-exfiltration-with-dns-query-analysis",
"detecting-email-account-compromise",
"detecting-email-forwarding-rules-attack",
"detecting-entra-offensive-tools-in-graph-logs",
"detecting-evasion-techniques-in-endpoint-logs",
"detecting-exfiltration-over-dns-with-zeek",
"detecting-fileless-attacks-on-endpoints",
"detecting-fileless-malware-techniques",
"detecting-golden-ticket-attacks-in-kerberos-logs",
"detecting-golden-ticket-forgery",
"detecting-indirect-prompt-injection",
"detecting-insider-data-exfiltration-via-dlp",
"detecting-insider-threat-behaviors",
"detecting-insider-threat-with-ueba",
"detecting-kerberoasting-attacks",
"detecting-lateral-movement-in-network",
"detecting-lateral-movement-with-splunk",
"detecting-lateral-movement-with-zeek",
"detecting-living-off-the-land-attacks",
"detecting-living-off-the-land-with-lolbas",
"detecting-malicious-npm-packages",
"detecting-malicious-scheduled-tasks-with-sysmon",
"detecting-mimikatz-execution-patterns",
"detecting-misconfigured-azure-storage",
"detecting-mobile-malware-behavior",
"detecting-modbus-command-injection-attacks",
"detecting-modbus-protocol-anomalies",
"detecting-model-extraction-attacks",
"detecting-network-anomalies-with-zeek",
"detecting-network-scanning-with-ids-signatures",
"detecting-ntlm-relay-with-event-correlation",
"detecting-oauth-token-theft",
"detecting-pass-the-hash-attacks",
"detecting-pass-the-ticket-attacks",
"detecting-port-scanning-with-fail2ban",
"detecting-privilege-escalation-attempts",
"detecting-process-hollowing-technique",
"detecting-process-injection-techniques",
"detecting-qr-code-phishing-with-email-security",
"detecting-ransomware-encryption-behavior",
"detecting-ransomware-precursors-in-network",
"detecting-rdp-brute-force-attacks",
"detecting-rootkit-activity",
"detecting-s3-data-exfiltration-attempts",
"detecting-secure-boot-bypass",
"detecting-serverless-function-injection",
"detecting-service-account-abuse",
"detecting-shadow-api-endpoints",
"detecting-shadow-it-cloud-usage",
"detecting-spearphishing-with-email-gateway",
"detecting-sql-injection-via-waf-logs",
"detecting-stuxnet-style-attacks",
"detecting-supply-chain-attacks-in-ci-cd",
"detecting-suspicious-oauth-application-consent",
"detecting-suspicious-powershell-execution",
"detecting-t1003-credential-dumping-with-edr",
"detecting-t1055-process-injection-with-sysmon",
"detecting-t1548-abuse-elevation-control-mechanism",
"detecting-typosquatting-packages",
"detecting-typosquatting-packages-in-npm-pypi",
"detecting-wmi-persistence",
"emulating-cloud-attacks-with-stratus-red-team",
"enumerating-cloud-with-cloudfox",
"eradicating-malware-from-infected-systems",
"evaluating-threat-intelligence-platforms",
"executing-active-directory-attack-simulation",
"executing-nist-rmf-authorization-to-operate",
"executing-phishing-simulation-campaign",
"executing-red-team-engagement-planning",
"executing-red-team-exercise",
"exploiting-active-directory-certificate-services-esc1",
"exploiting-active-directory-with-bloodhound",
"exploiting-adcs-with-certipy",
"exploiting-api-injection-vulnerabilities",
"exploiting-aws-with-pacu",
"exploiting-bgp-hijacking-vulnerabilities",
"exploiting-broken-function-level-authorization",
"exploiting-broken-link-hijacking",
"exploiting-constrained-delegation-abuse",
"exploiting-deeplink-vulnerabilities",
"exploiting-excessive-data-exposure-in-api",
"exploiting-http-request-smuggling",
"exploiting-idor-vulnerabilities",
"exploiting-insecure-data-storage-in-mobile",
"exploiting-insecure-deserialization",
"exploiting-ipv6-vulnerabilities",
"exploiting-jwt-algorithm-confusion-attack",
"exploiting-kerberoasting-with-impacket",
"exploiting-mass-assignment-in-rest-apis",
"exploiting-ms17-010-eternalblue-vulnerability",
"exploiting-nopac-cve-2021-42278-42287",
"exploiting-nosql-injection-vulnerabilities",
"exploiting-oauth-misconfiguration",
"exploiting-prototype-pollution-in-javascript",
"exploiting-race-condition-vulnerabilities",
"exploiting-server-side-request-forgery",
"exploiting-smb-vulnerabilities-with-metasploit",
"exploiting-sql-injection-vulnerabilities",
"exploiting-sql-injection-with-sqlmap",
"exploiting-template-injection-vulnerabilities",
"exploiting-type-juggling-vulnerabilities",
"exploiting-vulnerabilities-with-metasploit-framework",
"exploiting-websocket-vulnerabilities",
"exploiting-zerologon-vulnerability-cve-2020-1472",
"extracting-browser-history-artifacts",
"extracting-config-from-agent-tesla-rat",
"extracting-credentials-from-memory-dump",
"extracting-iocs-from-malware-samples",
"extracting-memory-artifacts-with-rekall",
"extracting-windows-event-logs-artifacts",
"fleet-hunting-with-velociraptor",
"generating-and-analyzing-sboms",
"generating-forensic-timelines-with-hayabusa",
"generating-threat-intelligence-reports",
"hardening-linux-endpoint-with-cis-benchmark",
"hardening-windows-endpoint-with-cis-benchmark",
"hunting-advanced-persistent-threats",
"hunting-bootkits-in-efi-system-partition",
"hunting-credential-stuffing-attacks",
"hunting-evtx-with-chainsaw",
"hunting-for-anomalous-powershell-execution",
"hunting-for-beaconing-with-frequency-analysis",
"hunting-for-cobalt-strike-beacons",
"hunting-for-command-and-control-beaconing",
"hunting-for-data-exfiltration-indicators",
"hunting-for-data-staging-before-exfiltration",
"hunting-for-dcom-lateral-movement",
"hunting-for-dcsync-attacks",
"hunting-for-defense-evasion-via-timestomping",
"hunting-for-dns-based-persistence",
"hunting-for-dns-tunneling-with-zeek",
"hunting-for-domain-fronting-c2-traffic",
"hunting-for-lateral-movement-via-wmi",
"hunting-for-living-off-the-cloud-techniques",
"hunting-for-living-off-the-land-binaries",
"hunting-for-lolbins-execution-in-endpoint-logs",
"hunting-for-ntlm-relay-attacks",
"hunting-for-persistence-mechanisms-in-windows",
"hunting-for-persistence-via-wmi-subscriptions",
"hunting-for-process-injection-techniques",
"hunting-for-registry-persistence-mechanisms",
"hunting-for-registry-run-key-persistence",
"hunting-for-scheduled-task-persistence",
"hunting-for-shadow-copy-deletion",
"hunting-for-spearphishing-indicators",
"hunting-for-startup-folder-persistence",
"hunting-for-supply-chain-compromise",
"hunting-for-suspicious-scheduled-tasks",
"hunting-for-t1098-account-manipulation",
"hunting-for-unusual-network-connections",
"hunting-for-unusual-service-installations",
"hunting-for-webshell-activity",
"hunting-saas-sso-token-abuse",
"implementing-aes-encryption-for-data-at-rest",
"implementing-alert-fatigue-reduction",
"implementing-anti-phishing-training-program",
"implementing-anti-ransomware-group-policy",
"implementing-api-abuse-detection-with-rate-limiting",
"implementing-api-gateway-security-controls",
"implementing-api-key-security-controls",
"implementing-api-rate-limiting-and-throttling",
"implementing-api-schema-validation-security",
"implementing-api-security-posture-management",
"implementing-api-security-testing-with-42crunch",
"implementing-api-threat-protection-with-apigee",
"implementing-application-whitelisting-with-applocker",
"implementing-aqua-security-for-container-scanning",
"implementing-attack-path-analysis-with-xm-cyber",
"implementing-attack-surface-management",
"implementing-aws-config-rules-for-compliance",
"implementing-aws-iam-permission-boundaries",
"implementing-aws-macie-for-data-classification",
"implementing-aws-nitro-enclave-security",
"implementing-azure-ad-privileged-identity-management",
"implementing-bgp-security-with-rpki",
"implementing-browser-isolation-for-zero-trust",
"implementing-canary-tokens-for-network-intrusion",
"implementing-cisa-zero-trust-maturity-model",
"implementing-cloud-trail-log-analysis",
"implementing-cloud-vulnerability-posture-management",
"implementing-cloud-waf-rules",
"implementing-cloud-workload-protection",
"implementing-code-signing-for-artifacts",
"implementing-conditional-access-policies-azure-ad",
"implementing-conduit-security-for-ot-remote-access",
"implementing-continuous-security-validation-with-bas",
"implementing-data-loss-prevention-with-microsoft-purview",
"implementing-ddos-mitigation-with-cloudflare",
"implementing-deception-based-detection-with-canarytoken",
"implementing-delinea-secret-server-for-pam",
"implementing-device-posture-assessment-in-zero-trust",
"implementing-devsecops-security-scanning",
"implementing-diamond-model-analysis",
"implementing-digital-signatures-with-ed25519",
"implementing-disk-encryption-with-bitlocker",
"implementing-dmarc-dkim-spf-email-security",
"implementing-ebpf-security-monitoring",
"implementing-email-sandboxing-with-proofpoint",
"implementing-end-to-end-encryption-for-messaging",
"implementing-endpoint-detection-with-wazuh",
"implementing-endpoint-dlp-controls",
"implementing-envelope-encryption-with-aws-kms",
"implementing-epss-score-for-vulnerability-prioritization",
"implementing-file-integrity-monitoring-with-aide",
"implementing-fuzz-testing-in-cicd-with-aflplusplus",
"implementing-gcp-binary-authorization",
"implementing-gcp-organization-policy-constraints",
"implementing-gdpr-data-protection-controls",
"implementing-gdpr-data-subject-access-request",
"implementing-github-advanced-security-for-code-scanning",
"implementing-google-workspace-admin-security",
"implementing-google-workspace-phishing-protection",
"implementing-google-workspace-sso-configuration",
"implementing-hardware-security-key-authentication",
"implementing-hashicorp-vault-dynamic-secrets",
"implementing-hipaa-security-rule-safeguards",
"implementing-honeypot-for-ransomware-detection",
"implementing-honeytokens-for-breach-detection",
"implementing-ics-firewall-with-tofino",
"implementing-identity-governance-with-sailpoint",
"implementing-identity-verification-for-zero-trust",
"implementing-iec-62443-security-zones",
"implementing-immutable-backup-with-restic",
"implementing-infrastructure-as-code-security-scanning",
"implementing-iso-27001-information-security-management",
"implementing-just-in-time-access-provisioning",
"implementing-jwt-signing-and-verification",
"implementing-llm-guardrails-for-security",
"implementing-log-forwarding-with-fluentd",
"implementing-log-integrity-with-blockchain",
"implementing-memory-protection-with-dep-aslr",
"implementing-microsegmentation-with-guardicore",
"implementing-mimecast-targeted-attack-protection",
"implementing-mitre-attack-coverage-mapping",
"implementing-mobile-application-management",
"implementing-mtls-for-zero-trust-services",
"implementing-nerc-cip-compliance-controls",
"implementing-network-access-control",
"implementing-network-access-control-with-cisco-ise",
"implementing-network-deception-with-honeypots",
"implementing-network-intrusion-prevention-with-suricata",
"implementing-network-segmentation-for-ot",
"implementing-network-segmentation-with-firewall-zones",
"implementing-network-traffic-analysis-with-arkime",
"implementing-network-traffic-baselining",
"implementing-next-generation-firewall-with-palo-alto",
"implementing-ot-incident-response-playbook",
"implementing-ot-network-traffic-analysis-with-nozomi",
"implementing-pam-for-database-access",
"implementing-passwordless-auth-with-microsoft-entra",
"implementing-passwordless-authentication-with-fido2",
"implementing-patch-management-for-ot-systems",
"implementing-patch-management-workflow",
"implementing-pci-dss-compliance-controls",
"implementing-policy-as-code-with-open-policy-agent",
"implementing-privileged-access-management-with-cyberark",
"implementing-privileged-access-workstation",
"implementing-privileged-session-monitoring",
"implementing-proofpoint-email-security-gateway",
"implementing-purdue-model-network-segmentation",
"implementing-ransomware-backup-strategy",
"implementing-ransomware-kill-switch-detection",
"implementing-rapid7-insightvm-for-scanning",
"implementing-rsa-key-pair-management",
"implementing-runtime-application-self-protection",
"implementing-saml-sso-with-okta",
"implementing-scim-provisioning-with-okta",
"implementing-secret-scanning-with-gitleaks",
"implementing-secrets-management-with-vault",
"implementing-secrets-scanning-in-ci-cd",
"implementing-security-chaos-engineering",
"implementing-security-information-sharing-with-stix2",
"implementing-security-monitoring-with-datadog",
"implementing-semgrep-for-custom-sast-rules",
"implementing-siem-correlation-rules-for-apt",
"implementing-siem-use-case-tuning",
"implementing-siem-use-cases-for-detection",
"implementing-sigstore-for-software-signing",
"implementing-soar-automation-with-phantom",
"implementing-soar-playbook-for-phishing",
"implementing-soar-playbook-with-palo-alto-xsoar",
"implementing-stix-taxii-feed-integration",
"implementing-syslog-centralization-with-rsyslog",
"implementing-taxii-server-with-opentaxii",
"implementing-threat-intelligence-lifecycle-management",
"implementing-threat-modeling-with-mitre-attack",
"implementing-ticketing-system-for-incidents",
"implementing-usb-device-control-policy",
"implementing-velociraptor-for-ir-collection",
"implementing-vulnerability-management-with-greenbone",
"implementing-vulnerability-remediation-sla",
"implementing-vulnerability-sla-breach-alerting",
"implementing-web-application-logging-with-modsecurity",
"implementing-zero-knowledge-proof-for-authentication",
"implementing-zero-standing-privilege-with-cyberark",
"implementing-zero-trust-dns-with-nextdns",
"implementing-zero-trust-for-saas-applications",
"implementing-zero-trust-in-cloud",
"implementing-zero-trust-network-access",
"implementing-zero-trust-network-access-with-zscaler",
"implementing-zero-trust-with-beyondcorp",
"implementing-zero-trust-with-hashicorp-boundary",
"integrating-dast-with-owasp-zap-in-pipeline",
"integrating-sast-into-github-actions-pipeline",
"intercepting-mobile-traffic-with-burpsuite",
"investigating-insider-threat-indicators",
"investigating-phishing-email-incident",
"investigating-ransomware-attack-artifacts",
"managing-cloud-identity-with-okta",
"managing-intelligence-lifecycle",
"managing-third-party-vendor-risk",
"mapping-attack-paths-with-bloodhound-ce",
"mapping-mitre-attack-techniques",
"migrating-to-post-quantum-cryptography",
"modeling-threats-with-opencti",
"monitoring-darkweb-sources",
"monitoring-scada-modbus-traffic-anomalies",
"moving-laterally-with-netexec",
"operating-havoc-c2",
"operating-sliver-c2",
"operationalizing-misp-threat-feeds",
"orchestrating-llm-attacks-with-pyrit",
"parsing-artifacts-with-eric-zimmerman-tools",
"performing-access-recertification-with-saviynt",
"performing-access-review-and-certification",
"performing-active-directory-bloodhound-analysis",
"performing-active-directory-compromise-investigation",
"performing-active-directory-forest-trust-attack",
"performing-active-directory-penetration-test",
"performing-active-directory-vulnerability-assessment",
"performing-adversary-in-the-middle-phishing-detection",
"performing-agentless-vulnerability-scanning",
"performing-ai-driven-osint-correlation",
"performing-alert-triage-with-elastic-siem",
"performing-android-app-static-analysis-with-mobsf",
"performing-api-fuzzing-with-restler",
"performing-api-inventory-and-discovery",
"performing-api-rate-limiting-bypass",
"performing-api-security-testing-with-postman",
"performing-asset-criticality-scoring-for-vulns",
"performing-authenticated-scan-with-openvas",
"performing-authenticated-vulnerability-scan",
"performing-automated-malware-analysis-with-cape",
"performing-aws-account-enumeration-with-scout-suite",
"performing-aws-privilege-escalation-assessment",
"performing-bandwidth-throttling-attack-simulation",
"performing-binary-exploitation-analysis",
"performing-blind-ssrf-exploitation",
"performing-bluetooth-security-assessment",
"performing-brand-monitoring-for-impersonation",
"performing-clickjacking-attack-test",
"performing-cloud-asset-inventory-with-cartography",
"performing-cloud-forensics-investigation",
"performing-cloud-forensics-with-aws-cloudtrail",
"performing-cloud-incident-containment-procedures",
"performing-cloud-log-forensics-with-athena",
"performing-cloud-native-forensics-with-falco",
"performing-cloud-native-threat-hunting-with-aws-detective",
"performing-cloud-penetration-testing-with-pacu",
"performing-cloud-storage-forensic-acquisition",
"performing-container-image-hardening",
"performing-content-security-policy-bypass",
"performing-credential-access-with-lazagne",
"performing-cryptographic-audit-of-application",
"performing-csrf-attack-simulation",
"performing-cve-prioritization-with-kev-catalog",
"performing-dark-web-monitoring-for-threats",
"performing-deception-technology-deployment",
"performing-directory-traversal-testing",
"performing-disk-forensics-investigation",
"performing-dmarc-policy-enforcement-rollout",
"performing-dns-enumeration-and-zone-transfer",
"performing-dns-tunneling-detection",
"performing-dynamic-analysis-of-android-app",
"performing-dynamic-analysis-with-any-run",
"performing-endpoint-forensics-investigation",
"performing-endpoint-vulnerability-remediation",
"performing-entitlement-review-with-sailpoint-iiq",
"performing-external-network-penetration-test",
"performing-false-positive-reduction-in-siem",
"performing-file-carving-with-foremost",
"performing-firmware-extraction-with-binwalk",
"performing-firmware-malware-analysis",
"performing-fuzzing-with-aflplusplus",
"performing-gcp-penetration-testing-with-gcpbucketbrute",
"performing-gcp-security-assessment-with-forseti",
"performing-graphql-depth-limit-attack",
"performing-graphql-introspection-attack",
"performing-graphql-security-assessment",
"performing-hardware-security-module-integration",
"performing-hash-cracking-with-hashcat",
"performing-http-parameter-pollution-attack",
"performing-indicator-lifecycle-management",
"performing-initial-access-with-evilginx3",
"performing-insider-threat-investigation",
"performing-ioc-enrichment-automation",
"performing-ios-app-security-assessment",
"performing-iot-security-assessment",
"performing-ip-reputation-analysis-with-shodan",
"performing-jwt-none-algorithm-attack",
"performing-kerberoasting-attack",
"performing-lateral-movement-with-wmiexec",
"performing-linux-log-forensics-investigation",
"performing-log-analysis-for-forensic-investigation",
"performing-log-source-onboarding-in-siem",
"performing-malware-hash-enrichment-with-virustotal",
"performing-malware-ioc-extraction",
"performing-malware-persistence-investigation",
"performing-malware-triage-with-yara",
"performing-memory-forensics-with-volatility3",
"performing-memory-forensics-with-volatility3-plugins",
"performing-mobile-app-certificate-pinning-bypass",
"performing-mobile-device-forensics-with-cellebrite",
"performing-network-forensics-with-wireshark",
"performing-network-packet-capture-analysis",
"performing-network-traffic-analysis-with-tshark",
"performing-network-traffic-analysis-with-zeek",
"performing-nist-csf-maturity-assessment",
"performing-oauth-scope-minimization-review",
"performing-open-source-intelligence-gathering",
"performing-osint-with-spiderfoot",
"performing-ot-network-security-assessment",
"performing-ot-vulnerability-scanning-safely",
"performing-packet-injection-attack",
"performing-paste-site-monitoring-for-credentials",
"performing-phishing-simulation-with-gophish",
"performing-physical-intrusion-assessment",
"performing-plc-firmware-security-analysis",
"performing-post-quantum-cryptography-migration",
"performing-privacy-impact-assessment",
"performing-privilege-escalation-assessment",
"performing-privilege-escalation-on-linux",
"performing-privileged-account-access-review",
"performing-privileged-account-discovery",
"performing-purple-team-atomic-testing",
"performing-purple-team-exercise",
"performing-ransomware-response",
"performing-ransomware-tabletop-exercise",
"performing-red-team-phishing-with-gophish",
"performing-red-team-with-covenant",
"performing-s7comm-protocol-security-analysis",
"performing-sca-dependency-scanning-with-snyk",
"performing-scada-hmi-security-assessment",
"performing-second-order-sql-injection",
"performing-security-headers-audit",
"performing-serverless-function-security-review",
"performing-service-account-audit",
"performing-service-account-credential-rotation",
"performing-soap-web-service-security-testing",
"performing-soc-tabletop-exercise",
"performing-soc2-type2-audit-preparation",
"performing-sqlite-database-forensics",
"performing-ssl-certificate-lifecycle-management",
"performing-ssl-stripping-attack",
"performing-ssl-tls-inspection-configuration",
"performing-ssl-tls-security-assessment",
"performing-ssrf-vulnerability-exploitation",
"performing-static-malware-analysis-with-pe-studio",
"performing-steganography-detection",
"performing-subdomain-enumeration-with-subfinder",
"performing-supply-chain-attack-simulation",
"performing-thick-client-application-penetration-test",
"performing-threat-emulation-with-atomic-red-team",
"performing-threat-hunting-with-elastic-siem",
"performing-threat-hunting-with-yara-rules",
"performing-threat-intelligence-sharing-with-misp",
"performing-threat-landscape-assessment-for-sector",
"performing-threat-modeling-with-owasp-threat-dragon",
"performing-timeline-reconstruction-with-plaso",
"performing-user-behavior-analytics",
"performing-vlan-hopping-attack",
"performing-vulnerability-scanning-with-nessus",
"performing-web-application-firewall-bypass",
"performing-web-application-penetration-test",
"performing-web-application-scanning-with-nikto",
"performing-web-application-vulnerability-triage",
"performing-web-cache-deception-attack",
"performing-web-cache-poisoning-attack",
"performing-wifi-password-cracking-with-aircrack",
"performing-windows-artifact-analysis-with-eric-zimmerman-tools",
"performing-wireless-network-penetration-test",
"performing-wireless-security-assessment-with-kismet",
"performing-yara-rule-development-for-detection",
"post-exploiting-microsoft-graph-with-graphrunner",
"prioritizing-vulnerabilities-with-cvss-scoring",
"processing-stix-taxii-feeds",
"profiling-threat-actor-groups",
"recovering-deleted-files-with-photorec",
"recovering-from-ransomware-attack",
"red-teaming-llms-with-garak",
"relaying-ntlm-for-adcs-esc8",
"remediating-s3-bucket-misconfiguration",
"reverse-engineering-android-malware-with-jadx",
"reverse-engineering-dotnet-malware-with-dnspy",
"reverse-engineering-ios-app-with-frida",
"reverse-engineering-malware-with-ghidra",
"reverse-engineering-ransomware-encryption-routine",
"reverse-engineering-rust-malware",
"scanning-containers-with-trivy-in-cicd",
"scanning-iac-and-images-with-trivy",
"scanning-infrastructure-with-nessus",
"scanning-network-with-nmap-advanced",
"securing-agentic-ai-tool-invocation",
"securing-api-gateway-with-aws-waf",
"securing-aws-iam-permissions",
"securing-aws-lambda-execution-roles",
"securing-azure-with-microsoft-defender",
"securing-container-registry-images",
"securing-github-actions-workflows",
"securing-historian-server-in-ot-environment",
"securing-kubernetes-on-cloud",
"securing-remote-access-to-ot-environment",
"securing-serverless-functions",
"testing-android-intents-for-vulnerabilities",
"testing-api-authentication-weaknesses",
"testing-api-for-broken-object-level-authorization",
"testing-api-for-mass-assignment-vulnerability",
"testing-api-security-with-owasp-top-10",
"testing-cors-misconfiguration",
"testing-for-broken-access-control",
"testing-for-business-logic-vulnerabilities",
"testing-for-email-header-injection",
"testing-for-host-header-injection",
"testing-for-json-web-token-vulnerabilities",
"testing-for-open-redirect-vulnerabilities",
"testing-for-sensitive-data-exposure",
"testing-for-system-prompt-leakage",
"testing-for-xml-injection-vulnerabilities",
"testing-for-xss-vulnerabilities",
"testing-for-xss-vulnerabilities-with-burpsuite",
"testing-for-xxe-injection-vulnerabilities",
"testing-jwt-token-security",
"testing-mobile-api-authentication",
"testing-oauth2-implementation-flaws",
"testing-prompt-injection-in-rag-pipelines",
"testing-ransomware-recovery-procedures",
"testing-websocket-api-security",
"tracking-threat-actor-infrastructure",
"triaging-security-alerts-in-splunk",
"triaging-security-incident",
"triaging-security-incident-with-ir-playbook",
"triaging-vulnerabilities-with-ssvc-framework",
"triaging-windows-with-kape",
"validating-backup-integrity-for-recovery",
"validating-tpm-measured-boot-attestation",
"verifying-build-provenance-with-slsa-sigstore"
],
"body-max-lines": [
"building-automated-malware-submission-pipeline",
"building-identity-governance-lifecycle-process",
"detecting-anomalous-authentication-patterns",
"detecting-attacks-on-scada-systems",
"detecting-command-and-control-over-dns",
"detecting-living-off-the-land-attacks",
"detecting-modbus-command-injection-attacks",
"detecting-ntlm-relay-with-event-correlation",
"detecting-serverless-function-injection",
"hunting-for-dcom-lateral-movement",
"implementing-data-loss-prevention-with-microsoft-purview",
"implementing-google-workspace-admin-security",
"implementing-hashicorp-vault-dynamic-secrets",
"implementing-iec-62443-security-zones",
"implementing-passwordless-auth-with-microsoft-entra",
"implementing-zero-trust-with-hashicorp-boundary",
"performing-cloud-log-forensics-with-athena",
"performing-graphql-introspection-attack",
"performing-ics-asset-discovery-with-claroty",
"performing-oauth-scope-minimization-review",
"performing-ot-network-security-assessment",
"performing-plc-firmware-security-analysis",
"performing-purple-team-atomic-testing"
]
}

View File

@@ -0,0 +1,219 @@
#!/usr/bin/env python3
"""Lint SKILL.md descriptions for the qualities that drive agent routing.
The description is the ONLY signal an agent sees at discovery time, so it must
say what the skill does, when to fire, and -- critically -- when NOT to fire.
Skills whose descriptions overlap without a distinguishing negative trigger get
misrouted ("skill collision").
Rules
-----
name-matches-folder frontmatter name == directory name
desc-max-length description <= 1024 chars (agentskills.io limit)
desc-ends-punctuation ends in . ! ? ) " ' -- a truncation canary
desc-has-use-when carries an explicit trigger clause
desc-has-negative-trigger says what it is NOT for
body-max-lines SKILL.md <= 500 lines (Anthropic guidance)
Grandfathering
--------------
Known pre-existing failures live in tools/lint-baseline.json so CI can go green
today while the debt is paid down. A baselined skill that starts passing is
reported as a stale entry -- run --update-baseline to shrink the file. The
baseline can only ever shrink in review, never silently grow: any NEW failure
is a hard error.
Usage:
python tools/lint-descriptions.py --all
python tools/lint-descriptions.py --all --stats
python tools/lint-descriptions.py --update-baseline
python tools/lint-descriptions.py skills/<slug>
"""
from __future__ import annotations
import argparse
import json
import os
import re
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from skill_frontmatter import description_of, iter_skill_dirs, load_frontmatter, FrontmatterError
BASELINE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lint-baseline.json")
DESCRIPTION_MAX_CHARS = 1024
BODY_MAX_LINES = 500
SENTENCE_ENDINGS = ".!?)\"'"
# "Use when ...", "Use this skill when ...", "Use for ...", "Use during ..."
USE_WHEN_RE = re.compile(
r"\buse\s+(?:this\s+)?(?:skill\s+)?(?:when|whenever|for|during|after|before)\b",
re.IGNORECASE,
)
# "Do not use for X", "Don't use when Y", "Not for Z"
NEGATIVE_TRIGGER_RE = re.compile(
r"\b(?:do\s+not\s+use|don'?t\s+use|not\s+for\b|avoid\s+(?:this\s+)?(?:skill\s+)?for)\b",
re.IGNORECASE,
)
RULES = (
"name-matches-folder",
"desc-max-length",
"desc-ends-punctuation",
"desc-has-use-when",
"desc-has-negative-trigger",
"body-max-lines",
)
RED, GREEN, YELLOW, DIM, RESET = "\033[91m", "\033[92m", "\033[93m", "\033[2m", "\033[0m"
def check_skill(slug: str, skill_dir: str) -> dict[str, str]:
"""Return {rule_id: human message} for every rule this skill violates."""
skill_md = os.path.join(skill_dir, "SKILL.md")
violations: dict[str, str] = {}
try:
frontmatter = load_frontmatter(skill_md)
except FrontmatterError as exc:
return {"name-matches-folder": f"unparseable frontmatter: {exc}"}
name = str(frontmatter.get("name", "") or "")
if name != slug:
violations["name-matches-folder"] = f"name {name!r} != folder {slug!r}"
description = description_of(frontmatter)
if len(description) > DESCRIPTION_MAX_CHARS:
violations["desc-max-length"] = (
f"{len(description)} chars, max {DESCRIPTION_MAX_CHARS}")
if description and description[-1] not in SENTENCE_ENDINGS:
violations["desc-ends-punctuation"] = f"ends with {description[-40:]!r}"
if not USE_WHEN_RE.search(description):
violations["desc-has-use-when"] = "no trigger clause (add 'Use when ...')"
if not NEGATIVE_TRIGGER_RE.search(description):
violations["desc-has-negative-trigger"] = (
"no negative trigger (add 'Do not use for X - use <other-skill>.')")
with open(skill_md, encoding="utf-8") as handle:
line_count = sum(1 for _ in handle)
if line_count > BODY_MAX_LINES:
violations["body-max-lines"] = f"{line_count} lines, max {BODY_MAX_LINES}"
return violations
def collect(skills_dir: str = "skills") -> dict[str, dict[str, str]]:
return {slug: v for slug, d in iter_skill_dirs(skills_dir)
if (v := check_skill(slug, d))}
def load_baseline() -> dict[str, list[str]]:
if not os.path.isfile(BASELINE_PATH):
return {}
with open(BASELINE_PATH, encoding="utf-8") as handle:
return {k: v for k, v in json.load(handle).items() if not k.startswith("_")}
def write_baseline(violations: dict[str, dict[str, str]]) -> dict[str, list[str]]:
baseline = {rule: sorted(s for s, v in violations.items() if rule in v)
for rule in RULES}
baseline = {rule: slugs for rule, slugs in baseline.items() if slugs}
payload = {
"_comment": (
"Pre-existing lint failures, grandfathered so CI can gate new work today. "
"This file may only shrink. Never add a slug by hand -- fix the skill, then "
"run: python tools/lint-descriptions.py --update-baseline"
),
"_total_grandfathered": sum(len(s) for s in baseline.values()),
**baseline,
}
with open(BASELINE_PATH, "w", encoding="utf-8") as handle:
json.dump(payload, handle, indent=2)
handle.write("\n")
return baseline
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("target", nargs="?", help="a single skills/<slug> directory")
parser.add_argument("--all", action="store_true", help="lint every skill")
parser.add_argument("--stats", action="store_true", help="show per-rule totals")
parser.add_argument("--update-baseline", action="store_true",
help="rewrite lint-baseline.json from current state")
parser.add_argument("--skills-dir", default="skills")
args = parser.parse_args()
if not os.path.isdir(args.skills_dir):
print(f"ERROR: '{args.skills_dir}' not found. Run from the repository root.")
return 1
single_skill = bool(args.target) and not (args.all or args.update_baseline)
if single_skill:
slug = os.path.basename(args.target.rstrip("/\\"))
violations = {slug: v} if (v := check_skill(slug, args.target.rstrip("/\\"))) else {}
else:
violations = collect(args.skills_dir)
if args.update_baseline:
baseline = write_baseline(violations)
total = sum(len(s) for s in baseline.values())
print(f"Baseline written: {total} grandfathered violation(s) across "
f"{len(baseline)} rule(s) -> {os.path.relpath(BASELINE_PATH)}")
for rule in RULES:
if baseline.get(rule):
print(f" {rule:26s} {len(baseline[rule])}")
return 0
baseline = load_baseline()
new_failures: list[tuple[str, str, str]] = []
grandfathered = 0
for slug, rule_map in sorted(violations.items()):
for rule, message in sorted(rule_map.items()):
if slug in baseline.get(rule, []):
grandfathered += 1
else:
new_failures.append((slug, rule, message))
# Only meaningful over the whole tree: linting one skill says nothing about
# whether the other 816 baselined violations still stand.
stale = [] if single_skill else [
(rule, slug) for rule, slugs in baseline.items() for slug in slugs
if rule not in violations.get(slug, {})
]
if args.stats:
print("Violations by rule (grandfathered + new):")
for rule in RULES:
count = sum(1 for v in violations.values() if rule in v)
remaining = len(baseline.get(rule, []))
print(f" {rule:26s} {count:4d} baselined {remaining:4d}")
print()
for slug, rule, message in new_failures:
print(f"{RED}FAIL{RESET} {slug}: {YELLOW}{rule}{RESET} - {message}")
if stale:
print(f"\n{GREEN}{len(stale)} baselined violation(s) now pass.{RESET} "
f"Shrink the baseline: python tools/lint-descriptions.py --update-baseline")
for rule, slug in stale[:10]:
print(f" {DIM}fixed{RESET} {slug}: {rule}")
print(f"\n{'=' * 60}")
checked = 1 if single_skill else sum(1 for _ in iter_skill_dirs(args.skills_dir))
print(f"Skills: {checked} "
f"{RED}New failures: {len(new_failures)}{RESET} "
f"{YELLOW}Grandfathered: {grandfathered}{RESET}")
return 1 if new_failures else 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""Single source of truth for reading SKILL.md YAML frontmatter.
Every tool in this repository MUST read frontmatter through this module.
Why this exists
---------------
This repo previously carried three independent hand-rolled "YAML-ish" parsers
(the index generator, validate-skill.py, validate-agentskills.py). Each handled
a different subset of YAML scalar styles, and all of them silently truncated
multi-line descriptions to their first line.
A census of the 817 skills shows why that was fatal:
block scalar (description: >-) 43
single-quoted multiline 278
plain unquoted multiline 496
single-line 0
Only the 43 block-scalar files parsed correctly; 774 (94.7%) used a style the
hand-rolled parsers mishandled, and 604 descriptions shipped truncated in
index.json with no error and no warning.
PyYAML handles every scalar style, quoting form and escape correctly. Do not
reintroduce a regex-based frontmatter parser -- CI greps for that.
"""
from __future__ import annotations
import os
import re
from typing import Dict, Iterator, Tuple
import yaml
# Frontmatter is the block between the opening '---' and the next '---' that
# sits alone on its own line. Tolerates CRLF and a leading UTF-8 BOM.
_FRONTMATTER_RE = re.compile(r"\A?---[ \t]*\r?\n(.*?)\r?\n---[ \t]*(?:\r?\n|\Z)", re.DOTALL)
BACKUP_SUFFIX = ".bak"
class FrontmatterError(ValueError):
"""Raised when a SKILL.md has missing or unparseable frontmatter."""
def extract_block(text: str) -> str:
"""Return the raw YAML frontmatter block from a SKILL.md's text."""
match = _FRONTMATTER_RE.match(text)
if not match:
raise FrontmatterError("no YAML frontmatter block (file must start with '---')")
return match.group(1)
def parse(text: str) -> dict:
"""Parse a SKILL.md's full text into a frontmatter dict."""
try:
data = yaml.safe_load(extract_block(text))
except yaml.YAMLError as exc:
raise FrontmatterError(f"invalid YAML in frontmatter: {exc}") from exc
if data is None:
return {}
if not isinstance(data, dict):
raise FrontmatterError(f"frontmatter must be a mapping, got {type(data).__name__}")
return data
def load_frontmatter(skill_md_path: str) -> dict:
"""Read one SKILL.md and return its frontmatter as a dict."""
try:
with open(skill_md_path, encoding="utf-8") as handle:
text = handle.read()
except UnicodeDecodeError as exc:
raise FrontmatterError(f"not valid UTF-8: {exc}") from exc
return parse(text)
def description_of(frontmatter: dict) -> str:
"""Return the description as a single normalized line.
YAML preserves the newlines of a literal ('|') scalar and folds a folded
('>') one; collapsing whitespace here gives every style the same shape,
which is what index.json and the linters want to compare.
"""
return " ".join(str(frontmatter.get("description", "")).split())
def iter_skill_dirs(skills_dir: str = "skills") -> Iterator[Tuple[str, str]]:
"""Yield (slug, skill_dir) for every real skill, in sorted order.
Skips '*.bak' backup directories and any directory lacking a SKILL.md.
"""
for slug in sorted(os.listdir(skills_dir)):
if slug.endswith(BACKUP_SUFFIX):
continue
skill_dir = os.path.join(skills_dir, slug)
if not os.path.isdir(skill_dir):
continue
if not os.path.isfile(os.path.join(skill_dir, "SKILL.md")):
continue
yield slug, skill_dir
def load_all(skills_dir: str = "skills") -> Tuple[Dict[str, dict], Dict[str, str]]:
"""Load frontmatter for every skill.
Returns (frontmatter_by_slug, errors_by_slug). Callers decide whether a
parse failure is fatal; nothing is silently dropped.
"""
loaded: Dict[str, dict] = {}
errors: Dict[str, str] = {}
for slug, skill_dir in iter_skill_dirs(skills_dir):
try:
loaded[slug] = load_frontmatter(os.path.join(skill_dir, "SKILL.md"))
except FrontmatterError as exc:
errors[slug] = str(exc)
return loaded, errors

View File

@@ -0,0 +1,171 @@
#!/usr/bin/env python3
"""Regenerate the contributor avatar wall in README.md from the GitHub API.
Writes between the markers:
<!-- contributors:start -->
...generated...
<!-- contributors:end -->
Avatars are served from github.com/<login>.png rather than a third-party
contributor-image service. That is deliberate: a README image is fetched on
every page view, so an external host would be an uncontrolled dependency in the
most-viewed file in the repository. GitHub's own avatar endpoint has neither
problem, and GitHub proxies it through camo like any other image.
Usage:
python tools/update-contributors.py # rewrite README.md
python tools/update-contributors.py --check # exit 1 if out of date
"""
from __future__ import annotations
import argparse
import json
import os
import sys
import urllib.request
REPO = os.environ.get("GITHUB_REPOSITORY", "mukul975/Anthropic-Cybersecurity-Skills")
MAINTAINER = REPO.split("/")[0]
README = "README.md"
START = "<!-- contributors:start -->"
END = "<!-- contributors:end -->"
# Accounts that are bots or automation, excluded from the wall.
EXCLUDE_SUFFIXES = ("[bot]",)
EXCLUDE_LOGINS = {"github-actions", "dependabot", "pull"}
AVATAR_PX = 72
def _get(path: str):
req = urllib.request.Request(f"https://api.github.com/repos/{REPO}/{path}", headers={
"Accept": "application/vnd.github+json",
"User-Agent": "update-contributors",
})
token = os.environ.get("GITHUB_TOKEN")
if token:
req.add_header("Authorization", f"Bearer {token}")
with urllib.request.urlopen(req, timeout=30) as resp:
return json.load(resp)
def _keep(login: str) -> bool:
return bool(login) and not login.endswith(EXCLUDE_SUFFIXES) and login not in EXCLUDE_LOGINS
def fetch_contributors() -> list[dict]:
"""Every non-bot contributor, most contributions first.
Two endpoints, because one of them lies. /contributors carries the
authoritative contribution counts but is heavily cached — a merge can take
up to a day to show up there. /commits is live. So anyone whose commit is
already linked to their account but has not yet surfaced in /contributors
gets picked up from the commit list instead of waiting a day to be thanked.
Commits authored with an unlinkable email (a machine hostname such as
user@HOST.localdomain) have no `author` object and are skipped by both
paths. They never appear in GitHub's own contributor graph either, so the
wall matches what GitHub itself shows.
"""
people: list[dict] = []
page = 1
while True:
batch = _get(f"contributors?per_page=100&page={page}")
if not batch:
break
people.extend(batch)
if len(batch) < 100:
break
page += 1
known = {p.get("login") for p in people}
ranked = [p for p in people if p.get("type") != "Bot" and _keep(p.get("login", ""))]
# Catch anyone the cached endpoint has not caught up with yet.
recent: dict[str, int] = {}
for page in (1, 2):
for commit in _get(f"commits?per_page=100&page={page}") or []:
author = commit.get("author")
if not author or author.get("type") == "Bot":
continue
login = author.get("login", "")
if login in known or not _keep(login):
continue
recent[login] = recent.get(login, 0) + 1
for login, count in sorted(recent.items(), key=lambda kv: (-kv[1], kv[0])):
ranked.append({"login": login, "contributions": count})
return ranked
def render(people: list[dict]) -> str:
lines = ['<p align="center">']
for person in people:
login = person["login"]
count = person.get("contributions", 0)
plural = "" if count == 1 else "s"
title = f"{login} — maintainer" if login == MAINTAINER else f"{login} — {count} contribution{plural}"
lines.append(
f'<a href="https://github.com/{login}" title="{title}">'
f'<img src="https://github.com/{login}.png?size=100" '
f'width="{AVATAR_PX}" height="{AVATAR_PX}" alt="@{login}"></a>'
)
lines.append("</p>")
lines.append("")
lines.append(
f'<p align="center"><sub>{len(people)} contributors, ordered by contribution count · '
f'see the full <a href="https://github.com/{REPO}/graphs/contributors">contributor graph</a>'
"</sub></p>"
)
return "\n".join(lines)
def splice(readme: str, block: str) -> str:
if START not in readme or END not in readme:
raise SystemExit(
f"ERROR: {README} is missing the {START} / {END} markers. "
"Add them around the contributor wall."
)
head, rest = readme.split(START, 1)
_, tail = rest.split(END, 1)
return f"{head}{START}\n{block}\n{END}{tail}"
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--check", action="store_true",
help="exit 1 if README.md is out of date; do not write")
args = parser.parse_args()
if not os.path.isfile(README):
print(f"ERROR: {README} not found. Run from the repository root.")
return 1
people = fetch_contributors()
if not people:
print("ERROR: the API returned no contributors; refusing to blank the section.")
return 1
current = open(README, encoding="utf-8").read()
updated = splice(current, render(people))
if updated == current:
print(f"OK: contributor wall is current ({len(people)} contributors)")
return 0
if args.check:
print(f"ERROR: contributor wall is out of date ({len(people)} contributors). "
"Run: python tools/update-contributors.py")
return 1
with open(README, "w", encoding="utf-8", newline="") as handle:
handle.write(updated)
print(f"Updated contributor wall: {len(people)} contributors")
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,122 @@
#!/usr/bin/env python3
"""Validate SKILL.md frontmatter against the strict agentskills.io standard.
Reports, per skill, any deviation from tools/agentskills-skill.schema.json plus
the two constraints JSON Schema can't express (name == parent dir; no angle
brackets in frontmatter). READ-ONLY; never edits files.
Usage:
python3 tools/validate-agentskills.py # summary + report
python3 tools/validate-agentskills.py --json # machine-readable JSON
python3 tools/validate-agentskills.py --strict # exit 1 if any non-compliant
"""
import os, re, sys, json, glob
from collections import Counter
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from skill_frontmatter import description_of, load_frontmatter, FrontmatterError
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ALLOWED = {"name", "description", "license", "compatibility", "metadata", "allowed-tools"}
NAME_RE = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")
# The agentskills.io standard forbids reserved vendor words in a skill name.
# tools/agentskills-skill.schema.json names this script as the enforcement
# point, but the check was never actually implemented until now.
RESERVED_NAME_WORDS = ("anthropic", "claude")
def validate(path):
slug = os.path.basename(os.path.dirname(path))
problems = []
try:
fm = load_frontmatter(path)
except FrontmatterError as exc:
return slug, [str(exc)], []
keys = list(fm.keys())
if "name" not in keys:
problems.append("missing required key: name")
if "description" not in keys:
problems.append("missing required key: description")
name = str(fm.get("name", "") or "")
if name:
if not NAME_RE.match(name):
problems.append(f"name not lowercase-kebab-case: {name!r}")
if not (1 <= len(name) <= 64):
problems.append(f"name length {len(name)} out of 1..64")
if name != slug:
problems.append(f"name {name!r} != directory {slug!r}")
for reserved in RESERVED_NAME_WORDS:
if reserved in name.lower():
problems.append(f"name contains reserved word {reserved!r}: {name!r}")
desc = description_of(fm)
if desc:
if not (1 <= len(desc) <= 1024):
problems.append(f"description length {len(desc)} out of 1..1024")
elif "description" in keys:
problems.append("description empty")
# Angle brackets are an injection risk. Checking the PARSED values (rather
# than the raw text) means YAML block-scalar indicators like `>-` are never
# mistaken for content, so no indicator-stripping hack is needed.
for key, value in fm.items():
if isinstance(value, str) and ("<" in value or ">" in value):
problems.append(f"frontmatter value for {key!r} contains angle brackets "
"(injection risk / not allowed)")
break
# Additional top-level keys are PERMITTED by the standard (name+description
# are the only required fields). They are reported for information, not
# counted as compliance failures.
nonstd = [k for k in keys if k not in ALLOWED]
return slug, problems, nonstd
def main():
as_json = "--json" in sys.argv
strict = "--strict" in sys.argv
skills = sorted(glob.glob(os.path.join(REPO, "skills", "*", "SKILL.md")))
results = []
nonstd_hist = Counter()
compliant = 0
for p in skills:
slug, problems, nonstd = validate(p)
nonstd_hist.update(nonstd)
if not problems:
compliant += 1
results.append({"skill": slug, "compliant": not problems, "problems": problems})
noncompliant = [r for r in results if not r["compliant"]]
summary = {
"total": len(skills),
"compliant": compliant,
"noncompliant": len(noncompliant),
"nonstandard_key_frequency": dict(nonstd_hist.most_common()),
}
if as_json:
print(json.dumps({"summary": summary, "results": results}, indent=1))
else:
print(f"agentskills.io compliance: {compliant}/{len(skills)} compliant, "
f"{len(noncompliant)} non-compliant")
print("\nNon-standard top-level keys (count of skills carrying each):")
for k, n in nonstd_hist.most_common():
print(f" {k:20s} {n}")
# distinct problem types (excluding the per-key nonstd noise)
other = Counter()
for r in noncompliant:
for pr in r["problems"]:
if not pr.startswith("non-standard top-level key:"):
other[re.sub(r':.*$', '', pr)] += 1
if other:
print("\nOther (non-key) issues:")
for k, n in other.most_common():
print(f" {k}: {n}")
if strict and noncompliant:
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,208 @@
#!/usr/bin/env python3
"""Validate SKILL.md metadata for the Anthropic-Cybersecurity-Skills repository.
Usage:
python tools/validate-skill.py skills/my-skill/
python tools/validate-skill.py --all
"""
import os
import re
import sys
import glob
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from skill_frontmatter import load_frontmatter, FrontmatterError
# Kept in sync with the CI workflow (.github/workflows/validate-skills.yml),
# which now delegates to this script so there is a single source of truth.
REQUIRED_FIELDS = ["name", "description", "domain", "subdomain", "tags",
"version", "author", "license"]
# Canonical subdomain → set of accepted aliases (including canonical itself).
# When a skill uses an alias, the validator accepts it but the canonical form
# is the first entry in each group below. New skills should use the canonical.
_SUBDOMAIN_ALIASES = {
# identity
"identity-access-management": {"identity-access-management", "identity-and-access-management", "identity-security"},
# zero-trust
"zero-trust-architecture": {"zero-trust-architecture", "zero-trust"},
# OT/ICS
"ot-ics-security": {"ot-ics-security", "ot-security"},
# SOC / security ops
"soc-operations": {"soc-operations", "security-operations"},
# red team
"red-teaming": {"red-teaming", "red-team"},
# standalone (no aliases)
"web-application-security": {"web-application-security", "application-security"},
"network-security": {"network-security"},
"penetration-testing": {"penetration-testing", "offensive-security"},
"digital-forensics": {"digital-forensics"},
"malware-analysis": {"malware-analysis"},
"threat-intelligence": {"threat-intelligence"},
"cloud-security": {"cloud-security"},
"container-security": {"container-security"},
"cryptography": {"cryptography"},
"vulnerability-management": {"vulnerability-management"},
"compliance-governance": {"compliance-governance", "governance-risk-compliance"},
"devsecops": {"devsecops"},
"threat-hunting": {"threat-hunting"},
"incident-response": {"incident-response"},
"endpoint-security": {"endpoint-security"},
"phishing-defense": {"phishing-defense", "social-engineering-defense"},
"api-security": {"api-security"},
"mobile-security": {"mobile-security"},
"ransomware-defense": {"ransomware-defense"},
"threat-detection": {"threat-detection"},
"blockchain-security": {"blockchain-security"},
"data-protection": {"data-protection"},
"deception-technology": {"deception-technology"},
"hardware-firmware-security": {"hardware-firmware-security", "firmware-analysis", "firmware-security"},
"privacy-compliance": {"privacy-compliance"},
"purple-team": {"purple-team"},
"supply-chain-security": {"supply-chain-security"},
"wireless-security": {"wireless-security"},
"ai-security": {"ai-security"},
}
# Flat set of all accepted subdomain values (canonical + aliases).
ALLOWED_SUBDOMAINS: set = {v for group in _SUBDOMAIN_ALIASES.values() for v in group}
# Reverse map: alias → canonical (for warning messages).
_ALIAS_TO_CANONICAL: dict = {}
for canonical, aliases in _SUBDOMAIN_ALIASES.items():
for alias in aliases:
_ALIAS_TO_CANONICAL[alias] = canonical
KEBAB_RE = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")
# Minimum description length. Other repo tooling uses 50 chars; align here.
DESCRIPTION_MIN_CHARS = 50
RED = "\033[91m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
RESET = "\033[0m"
def validate_skill(skill_dir):
"""Validate a single skill directory. Returns list of error strings."""
errors = []
skill_md = os.path.join(skill_dir, "SKILL.md")
if not os.path.isfile(skill_md):
return [f"SKILL.md not found in {skill_dir}"]
try:
fm = load_frontmatter(skill_md)
except FrontmatterError as e:
return [str(e)]
except IOError as e:
return [f"Could not read SKILL.md: {e}"]
# Check required fields.
for field in REQUIRED_FIELDS:
if field not in fm:
errors.append(f"Missing required field: {field}")
# Validate name.
name = fm.get("name", "")
if name:
if not KEBAB_RE.match(name):
errors.append(
f"Name '{name}' is not valid kebab-case (lowercase letters, digits, hyphens only)"
)
if len(name) > 64:
errors.append(f"Name too long ({len(name)} chars, max 64)")
# Validate description.
desc = fm.get("description", "")
if isinstance(desc, list):
errors.append("Description must be a string value, not a list")
elif isinstance(desc, str):
if len(desc) < DESCRIPTION_MIN_CHARS:
errors.append(
f"Description too short ({len(desc)} chars, min {DESCRIPTION_MIN_CHARS})"
)
# No hard upper-limit enforced; multi-line folded scalars (>-) produce
# long strings that are valid and common in this repo.
# Validate domain.
domain = fm.get("domain", "")
if domain and domain != "cybersecurity":
errors.append(f"Domain must be 'cybersecurity', got '{domain}'")
# Validate subdomain.
subdomain = fm.get("subdomain", "")
if subdomain:
if subdomain not in ALLOWED_SUBDOMAINS:
errors.append(
f"Unknown subdomain '{subdomain}'. Allowed: {', '.join(sorted(ALLOWED_SUBDOMAINS))}"
)
else:
canonical = _ALIAS_TO_CANONICAL.get(subdomain, subdomain)
if subdomain != canonical:
# Warn (non-blocking) — alias is accepted but canonical is preferred
print(
f"{YELLOW}WARN{RESET} subdomain '{subdomain}' is an alias;"
f" canonical form is '{canonical}'"
)
# Validate tags.
tags = fm.get("tags", [])
if isinstance(tags, str):
tags = [tags]
if len(tags) < 2:
errors.append(f"Need at least 2 tags, got {len(tags)}")
return errors
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <skill-dir> | --all")
sys.exit(1)
if sys.argv[1] == "--all":
# Skip .bak backup directories — they are stale copies without a SKILL.md.
# glob may return OS-native separators, so normalize before checking.
skill_dirs = sorted(
d for d in glob.glob("skills/*/")
if not d.rstrip("/\\").endswith(".bak")
)
if not skill_dirs:
print("ERROR: No skill directories found. Run from the repository root.")
sys.exit(1)
else:
skill_dirs = [sys.argv[1].rstrip("/") + "/"]
total = 0
passed = 0
failed = 0
for skill_dir in skill_dirs:
if not os.path.isdir(skill_dir.rstrip("/")):
print(f"{RED}SKIP{RESET} {skill_dir} — not a directory")
continue
total += 1
errors = validate_skill(skill_dir.rstrip("/"))
name = os.path.basename(skill_dir.rstrip("/"))
if errors:
failed += 1
print(f"{RED}FAIL{RESET} {name}")
for e in errors:
print(f" {YELLOW}→ {e}{RESET}")
else:
passed += 1
print(f"{GREEN}PASS{RESET} {name}")
print(f"\n{'='*50}")
print(f"Total: {total} {GREEN}Passed: {passed}{RESET} {RED}Failed: {failed}{RESET}")
sys.exit(0 if failed == 0 else 1)
if __name__ == "__main__":
main()