Detection quality & safety: verification identity, precision/recall gate, ReDoS-proofing, source-map expansion - #1
Merged
Conversation
R4: generate_sarif_report now emits the complete detector catalog as SARIF reportingDescriptors (help text, CWE, security-severity) built from the live registry — so CI consumers (GitHub code scanning) always have full rule metadata, even on a clean scan. Results still resolve to described rules; unknown types keep the finding-derived fallback. +2 tests (suite 145->147). Adds docs/TECHNICAL-AUDIT-AND-ROADMAP.md: honest capability/gap analysis vs 2026 SOTA (TruffleHog/Gitleaks) and a sequenced, tested enhancement roadmap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6XK23ZKmYtCovRte9a73E
A verified credential now also yields a short, non-sensitive identity/scope label (GitHub @acct + token scopes, Stripe account + LIVE/charges, Slack workspace/user, OpenAI org, npm/GitLab/Telegram handle, SendGrid send-scope, Mailgun domain count) — the concrete blast radius an attacker inherits. - verifier.py: verifiers return (active, detail); new VerifyResult + verify_finding_detailed(); verify_finding() kept as string-only wrapper (backward compatible). Detail extraction is defensive and never includes the secret value; fails closed. - scanner.py: ValidatedFinding gains verified_detail; scan flow captures it. - report.py: HTML ('live access: …'), CSV (verified_detail column), and SARIF (identity appended after the literal [VERIFIED ACTIVE] token + property). - +7 tests. Suite 147 -> 154 green; ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6XK23ZKmYtCovRte9a73E
Adds backend/bench/: a labelled corpus (12 synthetic, correctly-shaped high-entropy positives + 15 placeholders/examples/high-entropy noise) and a runner that measures the deterministic detection layer (extract_secrets: regex + placeholder allowlist + entropy gate + base64 pass — no network/AI) and reports precision / recall / F1 / type-accuracy with per-miss diagnostics. - make bench: human-readable precision/recall report. - test_bench.py: CI gate — fails the build if precision/recall/F1 < 0.95 or any placeholder/noise is flagged (brand value: zero false positives). - Current: precision 1.000 · recall 1.000 · F1 1.000 · 0 FP. - All corpus secrets are SYNTHETIC (deterministically generated, not live). The harness caught a malformed OpenAI test key, confirming the detector correctly requires the real 'T3BlbkFJ' key structure. Suite 154 -> 158 green; ruff clean. Marks R1+R2 done in the roadmap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6XK23ZKmYtCovRte9a73E
- scanner: MAX_MATCHES_PER_PATTERN cap in _scan_text bounds the matches examined for any single detector on any single text (defence-in-depth against a crafted match-flood blob). - test_regex_safety.py: empirical wall-clock fuzz over all 54 detectors x 17 adversarial 50KB inputs (no pattern may exceed 0.75s — proves no catastrophic backtracking), a static nested-quantifier guard that gates future pattern additions, and a cap-engagement test. Suite 158 -> 161 green; ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6XK23ZKmYtCovRte9a73E
Decode a source map's embedded original source (sourcesContent) and scan it as real code with precise per-file attribution (app.js.map -> src/config.js). - scanner: extract_sourcemap_sources() (defensive JSON decode, bounded by MAX_SOURCEMAP_SOURCES) + looks_like_sourcemap(); run_scan now scans a map's decoded sources INSTEAD of the raw .map JSON when sourcesContent is present — better attribution, catches secrets escaped in the raw JSON, and removes the map's high-entropy 'mappings' VLQ blob as a false-positive source. Falls back to raw-body scan when a map has no usable sourcesContent. - env: SCAN_SOURCEMAP_CONTENT (default true), MAX_SOURCEMAP_SOURCES (200). - +6 tests; end-to-end loop verified (single attributed finding, no dup). Note: inline JSON (__NEXT_DATA__) and HTML comments were already covered (the full HTML body is scanned wholesale), so they are not reclaimed as 'new'. Suite 161 -> 167 green; ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6XK23ZKmYtCovRte9a73E
Add read-only whoami/validate verifiers for existing detectors that previously returned 'unsupported': Cloudflare (tokens/verify), DigitalOcean (/account), Datadog (/validate), Notion (/users/me), Linear (GraphQL viewer), Figma (/me), Postman (/me), Doppler (/me). Each extracts R1 identity where available, is strictly read-only, and fails closed. Chosen over adding new detectors on purpose: this widens the verification-first differentiator with zero new false-positive risk (no new regexes). README provider list updated to match. +6 tests. Suite green; ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6XK23ZKmYtCovRte9a73E
…ement Turn the engine work into a client-ready deliverable. generate_html_report now: - leads with a verification-EVIDENCE callout: each verified-active credential with its R1 identity/scope shown as 'confirmed live access' (the strongest client signal — proven live, not shape-matched). Only rendered when there is live proof. - adds a 'Verified Active' KPI tile (alert-styled when > 0). - adds an honest 'Detection quality' statement: verification-first + a labelled benchmark corpus with a precision/recall gate in CI. All additive; clean scans render no callout. +4 tests. Suite green; ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6XK23ZKmYtCovRte9a73E
First step from secret-scanner toward the fuller attack-surface scanner the
brand promises. New posture.py analyses the target root's own response for
security misconfigurations — pure passive analysis, no exploitation, no
third-party calls, fails closed:
- missing/weak headers: HSTS, CSP, X-Content-Type-Options, clickjacking
(X-Frame-Options / CSP frame-ancestors), Referrer-Policy, Permissions-Policy
- software version disclosure (Server / X-Powered-By)
- insecure cookies (missing Secure / HttpOnly)
Each PostureFinding carries severity/CWE/evidence/remediation.
- scanner: one passive GET on the root feeds analyze_security_headers();
result['posture_findings'] populated (SCAN_HTTP_POSTURE, default true).
- report: dedicated 'Security Posture & Misconfigurations' HTML section +
'Posture Issues' KPI tile — so even a clean credential scan returns
actionable ASM findings.
- +11 tests (pure analyzer, fetch path, report section). Suite green; ruff clean.
Follow-up (deferred, external network): CT-log subdomains, dangling-DNS,
posture in CSV/SARIF.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V6XK23ZKmYtCovRte9a73E
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A measured, tested capability pass over SecretNode, grounded in a fresh audit vs 2026 secret-scanning SOTA (TruffleHog/Gitleaks). Each change is an independent, shippable slice behind tests. The test suite grows 145 → 167, all green; ruff clean. Full analysis in
docs/TECHNICAL-AUDIT-AND-ROADMAP.md.@acct+ token scopes, Stripe account + LIVE/charges, Slack workspace/user, OpenAI org, npm/GitLab/Telegram handle, SendGrid send-scope, Mailgun domain count) — the concrete blast radius an attacker inherits. Surfaced in HTML (live access: …), CSV (verified_detailcolumn), and SARIF (appended after the literal[VERIFIED ACTIVE]token + a property). Backward-compatible:verify_finding()keeps its string API; newverify_finding_detailed()returnsVerifyResult. Detail is derived identity only — never the secret itself; defensive extraction; fails closed.backend/bench/— a labelled corpus (12 synthetic, correctly-shaped positives + 15 placeholders/examples/high-entropy noise), amake benchprecision/recall/F1 report, and a pytest CI gate (test_bench.py) that fails the build on a precision/recall regression. Current: precision 1.000 · recall 1.000 · F1 1.000 · 0 false positives. All corpus secrets are synthetic (deterministic, not live).MAX_MATCHES_PER_PATTERN) plus an automated gate: empirical wall-clock fuzz over all 54 detectors × 17 adversarial 50 KB inputs (no pattern may exceed 0.75s), a static nested-quantifier guard, and a cap-engagement test.sourcesContent) and scan it as real code with precise per-file attribution (app.js.map → src/config.js), instead of the raw.mapJSON when source is present — which also removes the map's high-entropymappingsVLQ blob as a false-positive source. Env-tunable (SCAN_SOURCEMAP_CONTENT,MAX_SOURCEMAP_SOURCES); fully defensive.Type of change
Checklist
ruff check backend/passespytestpasses (added/updated tests for the change) — 167 tests, all green (+22 this PR)severity,cwe, andremediation— n/a (no new detectors here)🤖 Generated with Claude Code
Generated by Claude Code