{"id":"9b40d3da-1665-4638-851f-6a71b29c406a","slug":"security-scan","kind":"skill","name":"security-scan","summary":"Security scanning skill for AI coding agents. CVE vulnerability detection, OWASP Top 10 code analysis, and dependency audits. Follows agentskills.io specification.","owner":"Ray0907","repoUrl":"https://github.com/Ray0907/security-scan","license":"MIT","licenseTier":"permissive","trust":"community","stars":18,"match":null,"fewStars":false,"format":"skill","createdAt":"2026-01-18T03:13:32.000Z","addedAt":"2026-10-14T06:08:31.201Z","logoUrl":"https://avatars.githubusercontent.com/u/29456968?u=1e5dcc82f8d152f17490eef147b837dd3e6a3a4a&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["developer-tools"],"tags":["claude-code","dependency-audit","owasp","sca","security","semgrep"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-17T07:08:14.373Z","sample":false,"url":"https://conduits.dev/tools/security-scan","language":"Python","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# Security Scan\n\n[![Agent Skills compatible](https://img.shields.io/badge/Agent%20Skills-compatible-blue)](https://agentskills.io)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Release](https://img.shields.io/github/v/release/Ray0907/security-scan)](https://github.com/Ray0907/security-scan/releases)\n[![Validate](https://github.com/Ray0907/security-scan/actions/workflows/validate.yml/badge.svg)](https://github.com/Ray0907/security-scan/actions/workflows/validate.yml)\n\nAn [Agent Skills](https://agentskills.io/specification) security workflow for AI coding agents.\nIt plans and runs read-only dependency audits, Semgrep code-pattern scans, infrastructure\nmisconfiguration checks, secret detection, and GitHub Actions audits, then normalizes everything\ninto one OWASP Top 10:2025 mapped report with fingerprints, baseline diffs, and SARIF output.\n\nSee the [changelog](CHANGELOG.md) for release history.\n\n## When to use this skill\n\n- Use this skill for a deterministic scanner baseline with reproducible evidence and normalized\n  findings.\n- Use Cloudflare's complementary\n  [security-audit-skill](https://github.com/cloudflare/security-audit-skill) for a logic-level\n  source audit.\n- For both, run this skill first and provide `security-findings.json` to the audit as prior evidence.\n\n## Safety Model\n\nScanning is read-only by default. The skill does not install tools, update dependencies, execute\nproject scripts, build images, or change global agent settings without explicit approval. Missing\nor failed scanners are reported as incomplete coverage, never as a clean result.\n\n## Installation\n\nWith the [Skills CLI](https://skills.sh), which installs into any supported coding agent:\n\n```bash\nnpx skills add Ray0907/security-scan\n# user-level instead of project-level\nnpx skills add Ray0907/security-scan --global\n```\n\nFor Claude Code without the CLI:\n\n```bash\ngit clone https://github.com/Ray0907/security-scan.git ~/.claude/skills/security-scan\n```\n\nRestart Claude Code, open `/plugin`, and verify `security-scan@skills-dir` is enabled. The bundled\nClaude Code plugin manifest points its skill directory at this repository root.\n\nOther clients use their own skills directory. Consult the client's documentation for its install\nlocation and invocation UI.\n\nCode scanning requires Python 3.10 or newer and Semgrep. Officially recommended Semgrep installs:\n\n```bash\npipx install semgrep\n# or\nuv tool install semgrep\n```\n\nDependency tools are needed only for ecosystems detected in the target repository. See\n[`references/SCANNERS.md`](references/SCANNERS.md) for commands and limitations.\n\n## Usage\n\nAsk naturally or use slash-command-style arguments if the client supports them:\n\n```text\nScan this repository for security issues.\n/security-scan\n/security-scan --deps-only\n/security-scan --code-only\n/security-scan --owasp A05\n/security-scan --severity critical,high\n/security-scan --export-bypass\n```\n\n`--deps-only` and `--code-only` are mutually exclusive. Persistent reminders are client-specific;\nthe skill will not claim `--auto-remind` is active until a supported hook or automation is chosen.\n\nThe local pipeline is:\n\n```bash\npython3 scripts/scan_plan.py . --pretty > plan.json\npython3 scripts/run_plan.py plan.json --out scan-evidence --semgrep\npython3 scripts/normalize_findings.py scan-evidence --out security-findings.unreviewed.json\n# Review findings and write verdicts.json keyed by fingerprint.\npython3 scripts/normalize_findings.py scan-evidence --verdicts verdicts.json \\\n  --out security-findings.json\npython3 scripts/validate_report.py security-findings.json\n```\n\nUnreviewed code findings must remain labeled unreviewed. Add `--baseline security-findings.json` on\nrepeat scans, or `--format sarif` when preparing output for GitHub code scanning.\n\n## Example\n\nA monorepo with a Bun app, an npm app, an `infra/` directory holding a Dockerfile and a Kubernetes\nmanifest, and a GitHub Actions workflow:\n\n```bash\npython3 scripts/scan_plan.py /work/app --exclude infra/legacy --pretty\n```\n\n```json\n{\n  \"excluded\": [\"infra/legacy\"],\n  \"projects\": [\n    {\n      \"kind\": \"ci\",\n      \"path\": \".\",\n      \"status\": \"ready\",\n      \"tool\": \"zizmor\",\n      \"coverage\": \"offline-audits-only\",\n      \"command\": [\"zizmor\", \"--format\", \"json\", \"--offline\", \".github/workflows\"]\n    },\n    {\n      \"kind\": \"secrets\",\n      \"path\": \".\",\n      \"status\": \"ready\",\n      \"tool\": \"gitleaks\",\n      \"coverage\": \"filesystem-only\",\n      \"command\": [\"gitleaks\", \"dir\", \".\", \"--no-banner\", \"--redact\", \"--report-format\", \"json\", \"--report-path\", \"-\"]\n    },\n    {\n      \"kind\": \"node\",\n      \"path\": \"bunapp\",\n      \"status\": \"ready\",\n      \"tool\": \"bun\",\n      \"command\": [\"bun\", \"audit\", \"--json\"]\n    },\n    {\n      \"kind\": \"container\",\n      \"path\": \"infra\",\n      \"status\": \"ready\",\n      \"tool\": \"trivy\",\n      \"coverage\": \"misconfiguration-only\",\n      \"evidence\": [\"pod.yaml\"],\n      \"command\": [\"trivy\", \"fs\", \"--format\", \"json\", \"--scanners\", \"misconfig\", \".\"]\n    },\n    {\n      \"kind\": \"node\",\n      \"path\": \"npmapp\",\n      \"status\": \"ready\",\n      \"tool\": \"npm\",\n      \"command\": [\"npm\", \"audit\", \"--json\"]\n    }\n  ],\n  \"root\": \"/work/app\",\n  \"schema_version\": 2\n}\n```\n\nAfter normalization and review, each finding keeps its native identity and adds normalized fields\nand an evidence-backed verdict:\n\n```json\n{\n  \"aliases\": [\"1097678\"],\n  \"confidence\": \"unknown\",\n  \"cwe\": [\"CWE-1321\"],\n  \"fingerprint\": \"26011568e34bedbe\",\n  \"fixed_versions\": [],\n  \"id\": \"GHSA-xvch-5gv4-984h\",\n  \"installed_version\": null,\n  \"line\": null,\n  \"location\": \"bun.lock\",\n  \"native_severity\": \"critical\",\n  \"normalized_severity\": \"critical\",\n  \"owasp_2025\": [\"A03\"],\n  \"package\": \"minimist\",\n  \"references\": [\"https://github.com/advisories/GHSA-xvch-5gv4-984h\"],\n  \"rule_id\": null,\n  \"source\": \"bun\",\n  \"summary\": \"Prototype Pollution in minimist\",\n  \"type\": \"dependency\",\n  \"verdict\": \"confirmed\",\n  \"verdict_evidence\": {\n    \"reason\": \"bun audit reports the locked minimist release in the vulnerable range and no fixed release is locked.\",\n    \"reviewed_at\": \"2026-09-16T00:00:00+00:00\",\n    \"reviewer\": \"security-reviewer\",\n    \"trace\": \"minimist -> bun.lock\",\n    \"unresolved_fact\": null\n  }\n}\n```\n\nA completed report records every scanner state explicitly:\n\n| Scanner | Status | Example detail |\n| --- | --- | --- |\n| npm audit | `clean` | No advisories found |\n| pip-audit | `findings` | 2 advisories found |\n| Semgrep | `failed` | Ruleset download timed out |\n| cargo-audit | `skipped` | Tool unavailable |\n| Trivy | `inconclusive` | No supported lockfile |\n\n## Supported Scanners\n\n| Target | Evidence | Tool |\n| --- | --- | --- |\n| Node.js | pnpm, Yarn, npm, or Bun lockfile | Matching package manager audit |\n| Python | Requirements or `pylock.*.toml` | `pip-audit` |\n| Fallback ecosystems | uv, Poetry, Pipenv, Dart, Elixir, Swift, .NET, Deno lockfile | OSV-Scanner |\n| Go | `go.mod` | `govulncheck` |\n| Rust | `Cargo.lock` | `cargo-audit` |\n| PHP | `composer.lock` | Composer audit |\n| Ruby | `Gemfile.lock` | `bundler-audit` |\n| Java | Maven or Gradle manifest | Trivy filesystem fallback |\n| Container | `Dockerfile*`, `Containerfile*` | Trivy misconfiguration scan |\n| Infrastructure as code | Terraform, Compose, Kubernetes YAML | Trivy misconfiguration scan |\n| Secrets | Repository filesystem | Gitleaks |\n| CI workflows | GitHub Actions YAML | Zizmor offline audits |\n\nA Dockerfile or Containerfile alone is not an image vulnerability inventory. Image scanning\nrequires an existing image supplied by the user; this skill does not build untrusted repositories\nduring a scan.\n\n## How It Works\n\n1. `scripts/scan_plan.py` recursively inventories supported projects and emits a JSON execution\n   plan without running a scanner.\n2. `scripts/run_plan.py` executes ready records without a shell and stores redacted evidence.\n3. `scripts/normalize_findings.py` parses scanner output, applies baselines and filters, and emits\n   JSON, SARIF, or Markdown.\n4. Review assigns `confirmed`, `needs_validation`, or `rejected` verdicts with evidence; omitted\n   verdicts remain unreviewed.\n5. The normalizer and `scripts/validate_report.py` enforce the published JSON report schema.\n6. Semgrep runs with `p/owasp-top-ten` and metrics disabled for code-pattern coverage.\n7. Findings retain native advisory IDs and are normalized to OWASP 2025 only when supported.\n8. Reports list every scanner as `clean`, `findings`, `failed`, `skipped`, or `inconclusive`.\n\nDetailed contracts:\n\n- [`references/SCANNERS.md`](references/SCANNERS.md): commands, exit handling, and NVD enrichment.\n- [`references/OWASP.md`](references/OWASP.md): 2025 categories and legacy-label translation.\n- [`references/REPORTING.md`](references/REPORTING.md): redaction, report schema, and false positives.\n\n## Development\n\nRun the deterministic tests and official format validator:\n\n```bash\npython3 -m unittest discover -s tests -v\nuvx --from skills-ref agentskills validate \"$(pwd)\"\n```\n\nValidate the external Semgrep ruleset separately:\n\n```bash\nsemgrep scan --config p/owasp-top-ten --validate --metrics=off\n```\n\n## Structure\n\n```text\nsecurity-scan/\n├── .claude-plugin/plugin.json\n├── .github/workflows/validate.yml\n├── docs/                       # Design documents\n├── schema/\n│   ├── run.schema.json\n│   ├── scan-plan.schema.json\n│   └── security-findings.schema.json\n├── scripts/\n│   ├── normalize_findings.py\n│   ├── redaction.py\n│   ├── run_plan.py\n│   ├── scan_plan.py\n│   └── validate_report.py\n├── tests/\n│   ├── fixtures/               # Minimal scanner output samples\n│   ├── test_normalize_findings.py\n│   ├── test_run_plan.py\n│   ├── test_scan_plan.py\n│   └── test_validate_report.py\n├── references/\n│   ├── OWASP.md\n│   ├── REPORTING.md\n│   └── SCANNERS.md\n├── CHANGELOG.md\n├── SECURITY.md\n├── SKILL.md\n├── README.md\n└── LICENSE\n```\n\n## Contributing\n\nContributions are welcome. Include a regression test for planner or runner behavior, and add a\nminimal fixture under `tests/fixtures/<tool>/` for any new or changed scanner parser. Run all\nvalidation commands before opening a pull request.\n\n## License\n\n[MIT](LICENSE)\n"}