Repository navigation
Bundled semgrep taint rules on by default, measured on a blind held-out set - #2063
Merged
Merged
Conversation
…ut set
Perun's deterministic security layer added nothing on top of raw semgrep: security_verify is triage, not a detector, and review_checks ran semgrep only with a local config. This change bundles taint rules for Python and JavaScript, runs them by default in review_checks, reads native semgrep JSON in security_verify, and adds the bench that measured it.
- templates/semgrep-taint/{py,js}.yml: request-sourced taint rules for SQL, command, path traversal, SSRF, XSS and template injection. Guards and sanitizers are bound to the sink argument and must exit.
- review_checks.sh: semgrep runs the bundled rules by default; REVIEW_SEMGREP_CONFIG overrides, and a missing bundle prints its own message.
- security_verify.py: native semgrep JSON input. OSS semgrep emits no dataflow trace, so its rows stay unverified with a note to trace the source by hand.
- docs/bench/sast-sca-1027: in-sample SAST/SCA bench (rules were tuned on it).
- docs/bench/sast-sca-heldout1-1027: blind fixture (20 planted vulnerabilities, 20 decoys) preregistered before scoring, plus pre- and post-review scores.
size-budget-raise: .claude/skills/deep-code-review/references/method-situational.md 43484→43585 bundled semgrep taint rules are the review_checks default
Tests: all scripts/ci-tests.d pass
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hi1ChtXVVrE8YEA2Ano93i
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
Perun's deterministic security layer added nothing on top of raw semgrep.
security_verifytriages findings rather than detecting them, andreview_checksran semgrep only when given a local config. This PR bundles taint rules, runs them by default and measures them on a blind held-out set.On the held-out set, the bundled rules plus semgrep's
p/defaultfind 19 of 20 planted vulnerabilities, against 15 of 20 forp/defaultalone. The cost is more false positives: 21 against 14.templates/semgrep-taint/{py,js}.yml: request-sourced taint rules for SQL injection, command injection, path traversal, SSRF, XSS and template injection. Guards and sanitizers are bound to the sink argument and must exit (raise, return or throw); host allowlists apply to SSRF only.review_checks.sh: semgrep uses the bundled rules by default.REVIEW_SEMGREP_CONFIGstill overrides them, and a missing bundle now prints its own message.security_verify.py: reads native semgrep JSON. OSS semgrep emits no dataflow trace (only the Pro engines do), so these rows stayunverifiedwith a note to trace the source by hand.docs/bench/sast-sca-1027: the in-sample SAST and SCA bench. The rules were tuned on it.docs/bench/sast-sca-heldout1-1027: a blind fixture with 20 planted vulnerabilities and 20 decoys. It was preregistered asprereg/sast-heldout1before any scoring and is checked against SHA256 sums.Results (TP / FP / FN)
p/defaultp/defaultCaveats:
p/defaultis unpinned; the post-review arms reuse the first run'sp/defaultoutput.Verification
Run on head a51ce46:
scripts/ci-tests.d/*.sh: 169/169 pass.bench_check.py --changed origin/mainis clean for both bench dirs. The in-sample bench'sledger.jsonlstates in its own text that the freeze is self-attested and not blind. This includestest_semgrep_taint.py, with negative cases for self-method, subscript source, unrelated guard,Map.get,document.body, non-exiting guard and braced guard.test-review-checks-semgrep-default.shis fail-closed:set -euo pipefail, a guardedmktemp, and no git commit outside its temp dir.land-release.sh --regenmakes no diff, andgit diff --checkis clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01Hi1ChtXVVrE8YEA2Ano93i