Files
Open_Ultra_SAST/.kiro/specs/propose-adjudicate-prove/brief.md
T
Marius Ciepluch 1ae41eea19 feat(propose-adjudicate-prove): overlay adjudicates inventory before prove
Regex inventory stays the proposer. MAP attaches promote/demote/unadjudicated/coverage
from intra-file taint (tree-sitter when a grammar parses, Python ast as last resort).
Deep sandboxes promotions only, ordered by the existing heuristic ranker plus optional
OpenRouter mechanism recall. The SAST pair slice scores overlay outcomes; the stage-1
detection gate and local pair gate stay inventory-only.
2026-09-04 13:57:33 +02:00

2.4 KiB

Brief: regex proposes, semantics adjudicates, sandbox proves

Problem

OpenUltraSAST already has three scan stages (quick inventory, standard map, deep regression), but only the first stage actually decides. Pattern rules propose sinks; the map ranks files; the sandbox can run recipes. Nothing in the middle answers “does this sink receive attacker-controlled data, or is it a Juliet-style good twin / dead assignment / hardcoded command?”

Calibration corpora (cheat-sheet fixtures, OWASP Benchmark true/false files, Juliet bad/good, CVE pairs) are nice: one CWE per file, named sinks, labeled counterparts. Real working trees are not: mixed languages, generated code, unparseable files, framework wrappers, comments, one-hop assignments (sql = f"…{x}"; cur.execute(sql)), and no ground-truth labels.

Measured honesty on the labeled SAST slice is about +9% Youden. Widening regex to chase that number will fire on every Runtime.exec and leak on OWASP-false / Juliet goodG2B.

Approach

Keep three roles, never collapse them:

  1. Propose — pattern rules + optional SARIF. Stage 1. Does not decide worth-fixing.
  2. Adjudicate — tree-sitter IR (multi-language) + taint facts; optional Joern CPG sidecar; Python stdlib parse only as last-resort fallback. Promote, demote, or unadjudicated.
  3. Budget — ranker + mechanism memory (JSONL + OpenRouter embeddings, hard CWE/language/tag filters) before prove. Not a verdict. Not TF-IDF. Not raw file-slice embeddings.
  4. Prove — sandbox only on promoted, reachable, budgeted candidates.

The primary in-scope target is a messy working tree the operator is writing, not a labeled benchmark. Known-vuln corpora remain calibration scoreboards (smoke 90/10, pair Youden, GitHub silent-on-fix). They do not define success on unlabeled code.

Scope

  • Semantic overlay as MAP-stage adjudication; tree-sitter is the prio engine (CLI/API, fail-closed). Joern optional. Embeddings tune prove order.
  • Explicit unadjudicated when parse or flow fails — do not treat silence as safe.
  • Sandbox prove only after promote.
  • Pair eval scores the overlay on the sast slice; smoke gate stays inventory-only.

Out of scope

  • Replacing pattern rules.
  • LLM as parse/taint engine.
  • Requiring Joern or embeddings for quick.
  • Using embedding similarity to silently drop promotions.
  • Auto-writing flow facts from the improve loop.