IMD FLOWPrepare my job
← All documentation

Adversarial self-review

English · Project documentationDownload .md ↓

This is a source/test review by the implementing agent, not an independent audit. Scope: local router, interfaces/config, unit/fuzz/invariant/fork tests, deployment scripts, frontend validation/signing/proxy. Upstream protocol code was inspected for integration behaviour; not comprehensively re-audited.

Findings and fixes

IDSeverityAffected locationPreconditions / attack or failure pathImpactProof / fix
A01Medium, fixedsrc/IMDUniversalPaymentRouter.sol:129A manager integration returning a settled amount different from value was not explicitly checkedAccounting assumptions could be silently weakened by an incompatible managerSlither unused-return; now require settlement return equals spent. testSettlementMismatchAtomic proves rollback
A02Medium, fixedfrontend/lib/payment.ts:84Current x402 core rejects non-default assets unless opted in; initial integration followed documentation example without that additionA user could acquire IMD but be unable to start paymentSDK sequence test initially failed; add exact IMD allowedAssets entry with quote amount cap. SDK sequence test now passes
A03Medium, fixedfrontend/app/page.tsx:283 and pay():441API prepares/normalizes input after the user's draftSigning a different prepared action without informed review, or blocking all normalized actionsFetch initial challenge, save/display prepared input, require review checkbox; subsequent challenge input must equal reviewed canonical input
A04Medium, mitigatedfrontend/lib/server.ts:6; app/api routesPublic unauthenticated proxy requests consume upstream quotaAvailability/resource exhaustionFixed destinations, allowlists, timeout, 64-KiB bound, batch cap and 120/min process budget. Public hosting still requires edge/global rate controls; request-budget denial is an accepted availability tradeoff
A05Low, fixed in teststest/IMDUniversalPaymentRouterFork.t.sol:22Deterministic test deployment address already has ETH in real chain snapshotIncorrect balance-equals-zero assertion masked otherwise valid fork purchaseRecord pre-existing balance and prove each purchase preserves it. No production refund code was changed to sweep that ETH

Analyzer findings with High/Medium labels

Initial 66 reports included the fixed A01. Final 65 reports are fully listed in STATIC_ANALYSIS.md. The refund warning is High in the tool but false positive after accounting/reentry review. Two High shift and 22 Medium rounding warnings are in pinned upstream functions not invoked by router. They remain visible; no suppression configuration was added.

The refund target cannot be set by arbitrary calldata: it is msg.sender. Spending and refund total msg.value; nonReentrant prevents nested purchases. Forced ETH is excluded. Regression tests include rejected refunds, reentrancy, sequential users, partial output, reported-but-not-delivered output and max-input rollback.

Attack-surface review

AreaEvidence / conclusion
Wrong PoolKey / managerFixed verified fields; constructor compares hook getters and independently hashed key/id; fork uses actual deployments
Hook exact-output assumptionsafterSwap returns zero delta, flags forbid return-delta adjustments; source bytecode matches chain; real Quoter and actual purchase agree in fork
ETH accounting / forced ETHNo balance sweep, no arbitrary recipient refund, funding exactly max; baseline preserved in real fork and stateful tests
WETH transformationsNone in V1; native ETH pool verified
Exact-output / partial liquidityPositive amountSpecified; output delta equality then recipient balance delta; partial fill mock reverts; max failure fork has no partial delivery
Slippage / sandwichFixed max spend, deadline and preflight simulation; adverse execution within chosen tolerance remains possible
Signed casts / integer limitsint128 maximum output bound, positive output before cast, widen input before negation; uint256 subtraction only after amount checks
Callback / reentrancyFixed manager + active purchase + context hash; one-shot deletion; altered/replayed/missing callbacks and malicious refund receiver tested
Recipient contractsSupported by Solidity; can reject refund if also caller, atomically reverting. Standard IMD has no transfer receiver callback. UI payment signing supports EOA only
Token balance assumptionsActual inherited ERC20 transfer inspected; not tax/rebase token. Bridge/operator compromise remains outside scope
Denial of serviceRejected refund affects caller's operation; hook owner can remove liquidity; frontend proxies bounded but public edge limits required
Malicious frontend parametersSolidity enforces amounts/deadline/fixed path. User still must trust displayed destination and wallet confirmation; frontend cannot override wallet consent
Owner/admin / approvalsNone in router. x402 allowance separate, exactly quote amount, official Permit2 only; SDK unlimited helper not used
x402 / quote manipulationSame account, chain/token/destination/quote/resource binding, canonical hash, strict shape, checked Permit2 domain/types/spender and expiry before signing
Stale capabilitiesRefetch at quote creation; compare current price; saved quote/challenge governs payment; expired quote rejected. Stale swap estimate >30s rejected
Replay / retryPreserve exact signed payload for same order/account, fetch status first; never automatically create fresh permit on retry
Server key custodyNone; browser wallet signs, RPC method allowlist excludes broadcast. Secrets not logged by application code

Verification after fixes

Foundry 48 passing aggregate tests; this includes 35 unit, 3 fuzz, one aggregate invariant campaign with two properties, and 9 fork tests. Fork fuzz: 256 samples. Invariant campaign: 128 sequences / 4096 handler calls / 0 reverts. Frontend 19 tests including actual pinned SDK flow with a fake signer and proxy rejection cases. Typecheck/build pass. See evidence logs; initial failure logs are diagnostic history, not final status.

No confirmed unmitigated Critical/High code finding identified in this self-review. This is not proof of absence. Mainnet deployment, human-wallet acceptance and live paid settlement were not performed. External market owner powers, bridge trust, MEV, frontend hosting integrity and API availability remain material limitations.