Fixed (2026-06-04) a class of false needs_review rows in the LLM exploit stage: when Slither flags a PROXY contract’s OWN code, the exploit stage was analyzing only the implementation source, so the flagged snippets weren’t present and the contract got parked. Now fetch_analysis_source MERGES proxy + implementation source so Claude always sees both.

Gotcha — Slither flags the proxy, exploit stage fetches the implementation

The daily Slither scanner sometimes flags a PROXY contract’s own code — e.g. incorrect-return on an OpenZeppelin TransparentUpgradeableProxy’s ifAdmin functions (upgradeTo, changeAdmin, admin, implementation, upgradeToAndCall) and the ifAdmin modifier. That detector is a textbook false positive: the proxy returns via inline assembly, so incorrect-return misfires on functions that declare named returns.

But the exploit stage’s fetch.fetch_resolved_source ALWAYS follows a proxy to its implementation and analyzes THAT. So when the finding is about the proxy’s own code, the flagged snippets are NOT in the implementation source — build_source correctly reports them missing and the contract is parked as needs_review. It is not a size/budget truncation.

Concrete case

  • Contract 0x9334e37f… — a TransparentUpgradeableProxy.
  • Implementation is Swych (0xb500…), 132k chars, under the 200k budget — so it was NOT a budget truncation, despite the old message saying “source too large.”
  • Proxy resolution is nondeterministic across fetches: the implementation pointer (Etherscan getsourcecode Implementation field) varies between calls. This is why an earlier manual check saw the proxy source and a later run saw the implementation.

Fix

New fetch.fetch_analysis_source(client, base_url, chainid, address, api_key, limiter):

  • For a verified proxy with a verified implementation, returns a SourceResult whose .files MERGES both source sets with namespaced keys:
    • [proxy] <path> — the proxy’s own files
    • [impl] <path> — the implementation’s files
  • Non-proxy, or unverified implementation → returns the plain source unchanged.

The exploit stage’s _resolved_source_text now calls this instead of fetch_resolved_source (which is left intact). So Claude always sees BOTH the proxy and implementation source — the flagged code is present regardless of which layer it’s in, and Claude gets fuller context (admin/upgrade surface + logic) for judging proxy exploitability. build_source’s finding-first ordering protects the flagged files if a future merge exceeds the 200k budget.

The needs_review message was corrected from the misleading “source too large / could not be fully included in the source budget” to an honest “flagged code not found in the fetched proxy/implementation source within the budget.”

Validation

  • Re-ran 0x9334 live (python -m scanner.exploit --address 0x9334…) → now analyzedfalse_positive (Informational, High confidence), all 6 findings judged, with a rationale that correctly explains the ifAdmin assembly-return FP — proving Claude saw the proxy code via the merge.
  • After this fix plus clearing a separate stale 06-03 orphan row (0x528d…, which had dropped out of the current High-findings batch — deleted), bsc_contract_analysis is now 16 rows, all false_positive, 0 needs_review.

Resolves the 2026-06-03 needs_review rows

The daily 06-03 run’s 2 needs_review rows are now fully explained: 0x9334 was this proxy/impl source mismatch (not size), and 0x528d had churned out of the High-findings batch. This refines the whitespace-normalization fix — that earlier fix addressed snippet matching against a single source set, but the proxy case is a different root cause (wrong source target entirely), addressed here.

Process

brainstorm/recommendation → plan (docs/superpowers/plans/2026-06-04-proxy-source-merge.md) → subagent TDD → 42 tests pass.

Not yet committed

Changes were unstaged at time of writing: scanner/fetch.py, scanner/exploit.py, tests/test_fetch_resolved.py, tests/test_exploit.py.