Fix 17 findings from deep code review (10 high + 7 medium) - #52
Merged
Conversation
Deep review of the Python port surfaced correctness, security, and robustness defects; each was reproduced before fixing and is covered by a regression test proven to fail against the pre-fix code. Security: - visualizer render_trace_html: stored XSS via unescaped trace data in the <script> JSON and DOM (completes the 0.6.1 escaping work it missed) - action/run_gate: CI gate bypass via fixed $GITHUB_OUTPUT heredoc delimiter and unbounded step-summary code fence - llama_index: api_key/secret leakage from captured serialized config - ui_server: DNS-rebinding exposure of trace data (no Host validation) Correctness: - query: nested AND/OR/missing_step compiled without precedence, diverging the SQLite backend from the in-memory evaluator - write_buffer: per-run depth counter drifted after global eviction, over- shedding a run's events - instrument: @Traced generators recorded a spurious CRITICAL error on normal early termination (GeneratorExit) - integrations/google_genai: nested calls attached to the grandparent span - alignment: strictest audit profile blind to reordering; reorder keyed on list position instead of the authoritative sequence - replay: span-cycle events silently dropped instead of orphaned - verification: cycle validator missed cycles on partial graphs and overflowed on deep valid chains - rules: UnregisteredToolRule failed open on a string registry Robustness/observability: - store: in-memory live consumer thread died on a raising subscriber - crewai / sqlite_store: log previously-silent failures - ui_server: serialize payloads via to_dict() (dead branch) Co-Authored-By: Claude Fable 5 <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.
Deep review of the Python port across six subsystems (core storage, query/graph, alignment, integrations, CLI/UI/CI, tests/packaging). Every fix here was reproduced before fixing and is covered by a regression test proven to fail against the pre-fix code. Full suite: 473 passed, 4 skipped; ruff + mypy clean.
High severity (10)
Security
render_trace_html— trace data (LLM/tool output) flowed unescaped into a<script>JSON block and into DOMinnerHTML. Now HTML-escaped server-side, JSON escaped so</script>can't break out, and client-side escaped beforeinnerHTML. This is the exact class 0.6.1 fixed inindex.html/report.pybut missed here.action/run_gate.py) — the multi-linesummary(embedding attacker-influenceable step ids) was written to$GITHUB_OUTPUTwith a fixed heredoc delimiter, so a crafted step name could close the heredoc early and injectpassed=true, silently passing a real regression. Now a random per-write delimiter + a step-summary fence sized past any backtick run.Correctness
query.py) — nestedAND/OR/missing_stepcompiled to flatINTERSECT/UNION/EXCEPT; SQLite's equal left-to-right precedence silently re-grouped them, diverging from the in-memory backend. Members are now isolated in sub-selects.write_buffer.py) — per-run counter written back stale after eviction, permanently over-shedding a run's events.@tracedgenerator false error (instrument.py) — early termination (GeneratorExit) recorded a spurious CRITICAL.error; now a clean.end(sync + async).parent_span_id.alignment_engine.py,alignment_interpreter.py) — the strictest audit profile was blind to reordering, and detection keyed on list position instead of the authoritativesequence. Now sorts by sequence and is mode-independent.replay.py) — span cycles/self-parents left events in neither the tree nor the orphan list; now surfaced as orphans.verification.py) — missed cycles on partial graphs and overflowed on deep valid chains; now seeds from all edge endpoints and is iterative.Medium severity (7)
api_keyin versions that ship it; secret-keyed values (nested included) are now redacted.Host/Origincheck left trace data reachable via DNS rebinding; loopback binds now enforce a loopback allowlist.UnregisteredToolRulefail-open — a string registry degradednot into substring matching; now compared as a single exact entry._json_serializabledead branch — serialized internal field names instead ofto_dict().Tests
19 regression tests added/updated across 13 files. Two
test_*_gatetests that pinned the buggy alignment behavior (reorder only caught by span-aware profiles) were rewritten to pin the corrected contract. Each new test was verified to fail against the unfixed code.See
CHANGELOG.md([Unreleased]) for the full annotated list.🤖 Generated with Claude Code