fix(assail): null-check-aware UncheckedAllocation + precise eval detectors#134
Merged
Merged
Conversation
…detectors Three precision fixes to the C/JS/Python/Shell analyzers that were producing false positives across the estate (surfaced triaging hyperpolymath/proven#68 and JoshuaJewell/paint-type#86): 1. UncheckedAllocation (C): the detector named "Unchecked" flagged EVERY `malloc(...)` regardless of a following NULL check, and emitted a line-less, file-level finding. It now scans per line, skips a malloc whose result is NULL-checked within a short window (`if (p == NULL)`, `if (!p)`, nullptr), and attaches a line number. Net effect: genuinely-guarded allocations stop firing, genuinely-unchecked ones still fire (new test), and the line number lets an inline `// panic-attack: accepted` marker suppress a reviewed site. This is why a real null-check fix (proven stubs.c) previously did not clear. 2. DynamicCodeExecution (JS/Python): `contains("eval(")` matched FFI symbol names like `proven_calculator_eval(`. Now word-boundary `\beval\s*\(` (and `\b(?:eval|exec)\s*\(` for Python) — genuine `eval(` still flagged. 3. CommandInjection (Shell): `contains("eval ")` matched the `--eval` CLI flag. Now matches the eval builtin only in statement position (`(?m)(?:^|[\s;&|(])eval[ \t]`) — `--eval`/`-eval` no longer flagged, the real shell eval builtin still is. All conservative (no new false negatives): a site is only treated as checked/benign on a clear signal. Verified end-to-end — proven: 1 active Critical/High -> 0 (stubs.c clears); paint-type: 36 -> 35 (the gossamer `--eval` benchmark FP clears; genuinely-unsafe vendored FFI + the irreducible believe_me axiom correctly remain). 4 new tests; full analyzer suite green (17/17); zero warnings. Refs #32, hyperpolymath/proven#68. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 34 issues detected
View findings[
{
"reason": "Issue in instant-sync.yml",
"type": "secret_action_without_presence_gate",
"file": "instant-sync.yml",
"action": "peter-evans/repository-dispatch",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "expect() in hot path (2 occurrences, CWE-754)",
"type": "expect_in_hot_path",
"file": "/home/runner/work/panic-attack/panic-attack/src/attestation/chain.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "unsafe block -- requires SAFETY comment (1 occurrences, CWE-676)",
"type": "unsafe_block",
"file": "/home/runner/work/panic-attack/panic-attack/src/jit_context.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "mem::transmute bypasses type safety with unchecked bit reinterpretation (12 occurrences, CWE-704)",
"type": "transmute",
"file": "/home/runner/work/panic-attack/panic-attack/src/jit_context.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "critical"
},
{
"reason": "expect() in hot path (4 occurrences, CWE-754)",
"type": "expect_in_hot_path",
"file": "/home/runner/work/panic-attack/panic-attack/src/assail/analyzer.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "unwrap() without prior check -- DoS via panic (1 occurrences, CWE-754)",
"type": "unwrap_without_check",
"file": "/home/runner/work/panic-attack/panic-attack/src/query/mod.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "unwrap() without prior check -- DoS via panic (4 occurrences, CWE-754)",
"type": "unwrap_without_check",
"file": "/home/runner/work/panic-attack/panic-attack/benches/scan_bench.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "expect() in hot path (2 occurrences, CWE-754)",
"type": "expect_in_hot_path",
"file": "/home/runner/work/panic-attack/panic-attack/benches/scan_bench.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "expect() in hot path (1 occurrences, CWE-754)",
"type": "expect_in_hot_path",
"file": "/home/runner/work/panic-attack/panic-attack/examples/attack_harness.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "unwrap() without prior check -- DoS via panic (9 occurrences, CWE-754)",
"type": "unwrap_without_check",
"file": "/home/runner/work/panic-attack/panic-attack/examples/vulnerable_program.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
hyperpolymath
added a commit
that referenced
this pull request
Jun 29, 2026
Documentation follow-up to #134 (the detector precision fix), which merged before these docs were added. - **Human**: `CHANGELOG.md` `[Unreleased]` → "Fixed — assail detector precision" entry. - **Machine**: `.machine_readable/6a2/STATE.a2ml` → `[session-2026-06-24]` block + `last-updated` bump. Records the null-check-aware `UncheckedAllocation`, word-boundary `eval(`, and statement-position shell `eval` fixes, with the verified end-to-end results (proven 1→0, paint-type 36→35). Docs-only. Refs #32. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Three precision fixes to the
assailanalyzers that produced false positives across the estate — found while triaging hyperpolymath/proven#68 and JoshuaJewell/paint-type#86, and the root cause of why genuine fixes didn't clear. All conservative: no new false negatives.1. UncheckedAllocation is now actually "unchecked"-aware (C)
The detector flagged every
malloc(...)regardless of a NULL check, and emitted a line-less, file-level finding. Now it:if (p == NULL),if (!p),nullptr);// panic-attack: acceptedmarker suppress a reviewed site (previously impossible: marker suppression is line-gated).This is precisely why a real null-check fix (proven
stubs.c) never cleared before.2. eval() detectors are word-boundary aware (JS / Python)
contains("eval(")matched FFI symbol names likeproven_calculator_eval(. Now\beval\s*\((and\b(?:eval|exec)\s*\(for Python). Genuineeval(still flagged.3. Shell
evalno longer matches the--evalCLI flagcontains("eval ")matched--eval. Now the eval builtin is matched only in statement position —(?m)(?:^|[\s;&|(])eval[ \t].--eval/-evalno longer flagged; the real shellevalbuiltin still is.Verification
tests/analyzer_tests.rs): null-checked malloc skipped; genuinely-unchecked still flagged; shell--evalflag not flagged but builtin is; FFI*_eval(not flagged but realeval()is.stubs.cclears; the genuine fix finally registers).--evalbenchmark FP clears; the 3 irreduciblebelieve_meaxioms + 32 genuinely-unsafe vendored Zig FFI correctly remain — no over-suppression).Refs #32, hyperpolymath/proven#68.
🤖 Generated with Claude Code