Skip to content

fix(core): critical-leak synthetic risk_vector hardcoded to stale 18-length RISK_SCHEMA - #1220

Merged
squid-protocol merged 1 commit into
mainfrom
fix/critical-leak-risk-vector-schema-drift
Aug 10, 2026
Merged

fix(core): critical-leak synthetic risk_vector hardcoded to stale 18-length RISK_SCHEMA#1220
squid-protocol merged 1 commit into
mainfrom
fix/critical-leak-risk-vector-schema-drift

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

What

galaxyscope.py's CRITICAL LEAKS synthetic-node path (forces a file flagged by the Aperture secrets scanner onto the 3D map even though it never went through normal parsing) built risk_vector as a hardcoded literal: [0.0] * 13 + [0.0, 0.0, 0.0, 0.0, 100.0] — an 18-element vector with a comment claiming "Index 17 is secrets_risk". RISK_SCHEMA is actually 13 elements now (secrets_risk at index 12), so this path has been emitting a 5-element-too-long risk_vector.

Harmless in isolation, but record_keeper.py's SQLite INSERT builds its column list from the live RISK_SCHEMA length — any file taking this path made record_mission() raise sqlite3.OperationalError: N values for M columns and abort --db-only output for the entire scan, not just that one file.

How found

Building a tree-sitter-based ground-truth accuracy pass for JavaScript (mirroring ast_accuracy_audit.py's Python methodology, #1200): galaxyscope <path> --db-only crashed scanning expressjs/express because its committed .npmrc trips the hardcoded-secrets detector. Isolated to this exact literal via a cursor.execute proxy dumping column/value counts at the failing INSERT (deterministic: fails on the file whose classification == "critical_secret_leak"), confirmed by reverting.

Fix

Size risk_vector from len(SignalProcessor.RISK_SCHEMA) (matching the sibling AI-MODEL-WEIGHTS synthetic-node path a few lines down, which already did this correctly) and set the secrets_risk slot by name lookup instead of a hardcoded index — mirroring the hit_vector/sec_hardcoded_secrets pattern already used right below it.

tests/core_engine/test_galaxyscope.py::test_synthetic_node_generation asserted risk_vector[17] == 100.0 — also stale, silently "correct" only by coincidence since the old 18-length hardcoded vector still had a real value at index 17. Updated to assert against the live RISK_SCHEMA length and the schema-resolved secrets_risk index, so a future RISK_SCHEMA resize can't silently reintroduce this drift.

Test plan

  • python -m pytest tests/core_engine/test_galaxyscope.py -q (45 passed)
  • python tests/tools/audit_check.py (ruff/mypy/dead-key/ast-accuracy all clear)
  • Reproduced against expressjs/express (v5.2.1) before/after: galaxyscope <path> --db-only now succeeds; .npmrc row correctly records risk_secrets_risk = 100.0

🤖 Generated with Claude Code

…length RISK_SCHEMA

galaxyscope.py's CRITICAL LEAKS synthetic-node path (forces a file flagged
by the Aperture secrets scanner onto the 3D map even though it never went
through normal parsing) built risk_vector as a hardcoded literal:
`[0.0] * 13 + [0.0, 0.0, 0.0, 0.0, 100.0]` -- an 18-element vector with a
comment claiming "Index 17 is secrets_risk". RISK_SCHEMA is actually 13
elements now (secrets_risk at index 12), so this path has been emitting a
5-element-too-long risk_vector for a while. Harmless on its own, but
record_keeper.py's SQLite INSERT builds its column list from the live
RISK_SCHEMA length -- any file taking this path made record_mission()
raise `sqlite3.OperationalError: N values for M columns` and abort
`--db-only` output entirely for the whole scan, not just that one file.

Found while building a tree-sitter-based ground-truth accuracy pass for
JavaScript (mirroring ast_accuracy_audit.py's Python methodology, #1200):
`galaxyscope <path> --db-only` crashed on expressjs/express because its
committed `.npmrc` trips the hardcoded-secrets detector. Reproduced,
isolated to this exact literal via a cursor.execute proxy that dumped the
column/value counts at the failing INSERT, confirmed by reverting it.

Fix: size risk_vector from `len(SignalProcessor.RISK_SCHEMA)` (matching
the sibling AI-MODEL-WEIGHTS synthetic-node path a few lines down, which
already did this correctly) and set the secrets_risk slot by name lookup
instead of a hardcoded index, mirroring the hit_vector/sec_hardcoded_secrets
pattern already used right below it.

tests/core_engine/test_galaxyscope.py::test_synthetic_node_generation
asserted `risk_vector[17] == 100.0` -- also stale, and silently correct by
coincidence since the old 18-length hardcoded vector still had a real value
at index 17. Updated to assert against the live RISK_SCHEMA length and the
schema-resolved secrets_risk index, so a future RISK_SCHEMA resize can't
silently reintroduce this drift.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

squid-protocol added a commit that referenced this pull request Aug 10, 2026
…pass (#1223)

* fix(core): critical-leak synthetic risk_vector hardcoded to stale 18-length RISK_SCHEMA

galaxyscope.py's CRITICAL LEAKS synthetic-node path (forces a file flagged
by the Aperture secrets scanner onto the 3D map even though it never went
through normal parsing) built risk_vector as a hardcoded literal:
`[0.0] * 13 + [0.0, 0.0, 0.0, 0.0, 100.0]` -- an 18-element vector with a
comment claiming "Index 17 is secrets_risk". RISK_SCHEMA is actually 13
elements now (secrets_risk at index 12), so this path has been emitting a
5-element-too-long risk_vector for a while. Harmless on its own, but
record_keeper.py's SQLite INSERT builds its column list from the live
RISK_SCHEMA length -- any file taking this path made record_mission()
raise `sqlite3.OperationalError: N values for M columns` and abort
`--db-only` output entirely for the whole scan, not just that one file.

Found while building a tree-sitter-based ground-truth accuracy pass for
JavaScript (mirroring ast_accuracy_audit.py's Python methodology, #1200):
`galaxyscope <path> --db-only` crashed on expressjs/express because its
committed `.npmrc` trips the hardcoded-secrets detector. Reproduced,
isolated to this exact literal via a cursor.execute proxy that dumped the
column/value counts at the failing INSERT, confirmed by reverting it.

Fix: size risk_vector from `len(SignalProcessor.RISK_SCHEMA)` (matching
the sibling AI-MODEL-WEIGHTS synthetic-node path a few lines down, which
already did this correctly) and set the secrets_risk slot by name lookup
instead of a hardcoded index, mirroring the hit_vector/sec_hardcoded_secrets
pattern already used right below it.

tests/core_engine/test_galaxyscope.py::test_synthetic_node_generation
asserted `risk_vector[17] == 100.0` -- also stale, and silently correct by
coincidence since the old 18-length hardcoded vector still had a real value
at index 17. Updated to assert against the live RISK_SCHEMA length and the
schema-resolved secrets_risk index, so a future RISK_SCHEMA resize can't
silently reintroduce this drift.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs: add JavaScript language-status doc, first tree-sitter-based §9 pass

Follows python.md's structure (language-status skill), extending its §9
"measured accuracy" methodology beyond Python for the first time using
tree-sitter-language-pack against real code -- exactly the path python.md's
own §9 proposed for scaling past Python's stdlib `ast`.

Measured against two corpora with different shapes (expressjs/express
v5.2.1: small, mostly top-level functions and middleware callbacks; and
GitGalaxy's own site/js/ WebGPU visualizer: heavily class-based). Confirms
#1209/#1216's args capture-group fix works on real code (100% args-count
exact match on every function found, both corpora) and surfaces:

- A blocking infra bug that crashed --db-only on any repo with a flagged
  secret (fixed same-day in #1220, needed before this measurement could
  run at all -- express's own committed .npmrc trips the detector).
- #1221 (open): func_start's method-shorthand branch has no trailing-`{`
  requirement, unlike args' own "Invocation Shield" for the same shape --
  bare call statements (`next();`) get misidentified as definitions.
  Confirmed to also affect typescript/java/csharp/apex/dart/groovy.
- #1222 (open): real, differently-named functions can be silently dropped
  from function_data even though func_start's regex finds them correctly --
  most severe for ES6 class methods (one file lost 9 of 10 real methods).
  Likely the same _slice_by_braces mechanism #789 diagnosed and left
  unfixed for csharp.

Neither new defect fixed here (docs-only pass, per the language-status
skill's scope discipline) -- both need the fuller harden-language-extraction
treatment given they touch shared detector.py slicing logic.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Joe Esquibel <squid-protocol@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@squid-protocol
squid-protocol merged commit e355ad9 into main Aug 10, 2026
29 checks passed
@squid-protocol
squid-protocol deleted the fix/critical-leak-risk-vector-schema-drift branch August 10, 2026 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant