All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Taint-mode semgrep presets for JavaScript (
presets/javascript.toml) and Go (presets/go.toml), with taint-source/sink rules for SQLi, command injection, and path traversal - Taint-mode rules added to existing PHP and Python presets
max_target_bytesconfig field under[scanner.semgrep]to cap file size passed to semgrep via--max-target-bytes- Graduated verification gate: individual check results (reachability, controllability, preconditions, context, impact) are recorded separately instead of a single binary kill
- Default
project.languagesinconfig.example.tomlexpanded from["c", "python"]to includego,javascript,php - Semgrep runner no longer aborts the entire scan on a non-zero exit code; partial JSON findings from stdout are preserved
- Verification gate downgrades to
NeedsReviewinstead ofFalsePositivewhen a single check fails, preserving incremental evidence
- Finding ID collisions:
generate_idnow includesrule_idand a snippet discriminator byte in the hash, preventing distinct vulnerabilities on the same file/line/CWE from sharing an ID generate_iddistinguishesNonefromSome("")snippets via a discriminator byte
First public release.
- VulnInstruct specification-guided vulnerability detection (
src/vuln_specmodule: schema, extractor, BM25+vector retriever) behind[vuln_spec] enabled = falsedefault baco report --config <PATH>to load evidence-gate config for standalone reports
-
baco doctorpre-flight checks: config parse, per-phase LLM slot validation (warns on phases withoutapi_keythat will be skipped), semgrep/python3 presence, output dir writability, disk space -
baco evaldetection-regression suite: 10 labeled targets with ground-truth oracles, precision/recall/F1, CI gate on pass-rate (BACO_EVAL_FLOOR, default 0.70) -
baco init [PATH]config scaffolding with language detection and preset suggestions -
Scan-health report (console + JSON section): per-phase run/skipped-with-reason, file counters (indexed/analyzed/dropped/chunked), LLM call outcomes by error class, blind-scan warning when all LLM phases are skipped
-
Pipeline profiles:
[scanner] profile = "core"(default, 23 phases) or"all"(experimental phases included) -
Presets:
django,laravel,cpp; inlinecustom_rulesSemgrep YAML in presets (self-contained detection packages) -
Per-language default Semgrep rulesets derived from
project.languages -
Environment-variable bridges for all six LLM phase slots (
LLM_DISCOVERY_KEY,LLM_VERIFICATION_KEY,LLM_AGGREGATION_KEY,LLM_STATIC_ANALYSIS_KEY,LLM_SECURITY_AGENT_VERIFICATION_KEY,LLM_THREAT_MODELING_KEY) -
Configurable never-submit confidence filter (
never_submit_enabled,never_submit_multiplier) -
max_reasoning_tokensfield for LLM config -
Agent scaffold modules:
call_graph_paths,fn_lookup -
Chunked analysis of oversized files via tree-sitter (previously dropped or truncated at 8 KB)
-
Config-driven per-language hook registry (
[knowledge.hook_registry.<language>]) andrequired_security_primitivesverification prompts
- Threat-modeling phase disabled by default (
enable_threat_modeling = false) — it generated a static STRIDE template rather than code-derived analysis - Pipeline defined once in a declarative PhaseSpec table (checkpoint transitions, profile filtering, progress messages and docs all derive from it)
- Semgrep severity read from
extra.severityfirst (ERROR/WARNING/INFO mapping);check_idkeywords can only raise, never lower - HTML report rendered via embedded minijinja templates
- LLM internals consolidated under
src/llm/(client, cache, metrics, traits) with canonical import paths max_file_size_kbdefaults to 512; early-termination threshold counts medium+ findings only- Verification batch parser accepts responses without
index(positional fallback with warning) - Multi-model round-robin preserved per phase (
modelslist no longer collapsed) - Internal refactoring: modules split into directory modules, shared tree-sitter parser, tests consolidated under
tests/
- LLM endpoint URL doubling (
/v1/v1/) causing silent 404s - Discovery phase dropping findings that already had LLM evidence
- API key printed in log output during static analysis
- HTML report broken by unclosed
<style>/<div>tags - Semgrep multi-hit findings attributed to placeholder
multiple_filespath - Custom-rule IDs prefixed with the materialized temp-file stem
- Discovery enrichment silently overwriting detector severity (enrichment is raise-only)
- LLM findings without a
linefield silently dropped (now salvaged with a warning) - JSON schema fields serialized as
type_instead oftype - C function-name extraction handles
function_declaratortree-sitter node - Call-graph builder treats uncalled functions as entry points
- MultiVerifier stub phase (fabricated hash-based verdicts)
- Dead modules: report aggregation, scan diff, worktree staging, severity rubric, phase scaffolding (~2,500 lines)
- Phantom
[llm.phases.*]config slots and unused configuration keys