Skip to content

Repository files navigation

🛡️ deep-security-check

A defensive, read-only security assessment for any local project — with a reproducible reliability grade.

Point it at a codebase. It runs best-in-class open-source scanners and returns a graded report (0–100, A–F) where the number comes from a deterministic rubric, not model opinion.

License: MIT Version Read-only Zero traffic to targets Claude Code

deep-security-check demo: scan a project, get a reproducible grade


Contents

💡 Why

Ask an AI "is this project secure?" and you get a plausible-sounding essay that changes every time you ask. That is not a measurement.

deep-security-check gives you a number you can reproduce and defend: a small Python script owns the scoring with fixed penalties and hard ceilings, so the same findings always produce the same grade. The model narrates the results — it never touches the number.

🚀 Quick start

/plugin marketplace add give-jd/deep-security-check
/plugin install deep-security-check@give-security

Then just ask Claude:

"How reliable is this project, security-wise?"

Installing from a local clone instead? /plugin marketplace add /path/to/security-scan-skill

🔍 What it runs

Layer Tool What it catches
SAST Semgrep — or Opengrep (LGPL fork) as a drop-in when semgrep is absent Injection, unsafe deserialization, weak crypto, CI/CD & IaC misconfig
SCA osv-scanner — trivy as fallback Known CVEs and malicious packages in your dependencies
Secrets gitleaks (vendored fallback bundled) Hardcoded credentials — in the working tree and the git history

Plus three advisory passes that never change the grade:

  • 🌐 Dynamic-test surface (surface.py) — a static, zero-traffic map of where a DAST run would look (permissive CORS, missing security headers, insecure cookies, debug/bind-all).
  • 🧱 Structure hygiene (structure.py) — README, LICENSE, tests, CI, lockfiles, pinned deps, committed .env, SECURITY.md, dependabot/renovate, Dockerfile root user.
  • 📦 SBOM — a CycloneDX artifact via syft when present.

📊 The grade

score.py owns the number, so it is deterministic. Start at 100, subtract capped per-severity penalties over all findings, then apply hard ceilings:

severity penalty each cap
🔴 critical 25 60
🟠 high 8 30
🟡 medium 1.5 15
⚪ low 0.25 6

Ceilings — any critical → score ≤ 69 · any high → score ≤ 84 · any malicious package → score ≤ 20.

Grade Range Meaning
A 90–100 Solid
B 80–89 Solid, minor debt
C 70–79 Manageable debt
D 60–69 Real risk
E 50–59 Real risk
F <50 Not trustworthy until fixed

assessment_confidence tells you how much to trust the score itself: high only when all three scanner classes ran. A one-shot static scan is never a substitute for a pentest — and the report says so.

Reproduce the rubric by hand, or run python3 …/score.py --selfcheck.

🧹 Noise reduction

So the grade reflects real risk, not scanner overlap:

  • Cross-scanner dedup — the same file:line flagged by two tools counts once.
  • Path-aware triage — findings under tests/, fixtures/, examples/, mocks/ … are downgraded one severity step (a hardcoded credential in a fixture is not a production leak).
  • Malware first — OSV MAL-* advisories are surfaced as malicious_packages, separate from CVEs, and hard-cap the score. A malicious dependency dominates everything.

The triage field in the report shows exactly what was deduped and downgraded.

Two more passes are opt-in via --project <dir> on score.py:

  • Reachability-lite — an SCA finding whose package name never appears in the source is downgraded one step (declared-but-unused). Heuristic and conservative: it never drops a finding, only downgrades on a confident zero-match.
  • .dsc-ignore — suppress accepted findings with a mandatory justification (<path-glob>:<ruleId-or-*> -- why). Suppressed findings are listed in the report with their reason; a rule missing its justification is rejected, not applied. Suppression stays visible, never silent.

🧰 Requirements

At least one scanner on your PATH — more installed → higher confidence:

Tool Install
Semgrep pipx install semgrep
osv-scanner releases
gitleaks releasesvendored fallback included

Optional, used automatically when present: trivy (SCA fallback), syft (SBOM), opengrep (drop-in SAST engine).

🔌 Works offline / behind a proxy

Egress-restricted environments (corporate proxies, the Claude Cowork sandbox) degrade gracefully instead of hanging or failing:

  • Semgrep registry unreachable → falls back to a bundled MIT ruleset (rules/offline-basic.yaml, ~30 high-precision rules incl. CI/CD & IaC). Reduced coverage — and the report says so.
  • gitleaks missing on Linux x86_64 → a checksum-verified vendored binary is used.
  • No SCA tool / OSV blocked → the report states plainly that dependency CVEs were not checked, and confidence is capped.

Knobs: DSC_SEMGREP_CONFIG (local ruleset), DSC_SEMGREP_TIMEOUT, DSC_TRIVY_OFFLINE, DSC_SKIP_HISTORY.

🖥️ Use it without Claude

The scripts are plain bash + Python with no project-specific dependencies:

OUT=$(bash skills/deep-security-check/scripts/scan.sh <project-dir> | grep '^OUT=' | cut -d= -f2)
python3 skills/deep-security-check/scripts/score.py --sarif-dir "$OUT"
python3 skills/deep-security-check/scripts/structure.py <project-dir>   # advisory

Re-scanning over time? Add --baseline <old.json> to score.py for a vs_baseline delta (improved / worsened, per-severity).

✅ Guarantees

  • Read-only. It reads the project and never modifies it.
  • Zero traffic to targets. It never sends network traffic to live or remote hosts. (Scanners may query package databases like OSV.dev with dependency names — see PRIVACY.md.)
  • Defensive only. For code you own or are authorized to inspect. Not a penetration test; DAST is intentionally out of scope for a publicly installable skill.

📄 License

MIT. See also PRIVACY.md · ROADMAP.md · SECURITY.md.

About

Defensive, read-only security assessment skill for Claude Code (Semgrep + osv-scanner + gitleaks) with a reproducible reliability grade (0-100, A-F).

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages