← back to build & deploy plan
Red-Team Report · adversarial · post-AUDIT, pre-deploy

Red-Team — break-it pass on the integrated stack Independent adversaries attacking the audited code to earn a guarantee, not a review. Target: stable-deploy-integrated @ 0d8c819e. Only confirmed-exploitable findings count.

TESTNET: GO ✓ MAINNET: CONDITIONAL — named items
Verdict: zero confirmed-exploitable defects. Two independent adversaries — one of which built a real hardhat attack harness (30 tests) — tried to break every audit invariant and the new FeeRouter. Nothing broke. The decisive structural fact: no on-chain contract consumes the reputation score to gate value, so every score-inflation attack has zero on-chain profit. The remaining items are centralization-hardening for mainnet, plus one ownership cleanup worth doing now.

Negative-control floor — PASSED (the method has teeth)

The red team caught a planted bug before any PASS was trusted

The adversary copied ReputationEngine.sol to a scratch file, removed the deregisterBot access-control check, and ran an unauthorized-deregister attack against both copies — checking revert AND state mutation. Planted-bug copy: attack succeeded (bug caught ✅). Real contract: attack reverted (resisted ✅). So the PASS verdicts below are trustworthy, not rubber stamps.

1

Per-target results — all PASS

TargetVerdictEvidence
M1 — attribution spoofPASSdeploy wires setReputationEngine before resolver is live; enforced at 3 points + pre/post-asserts; an unwired resolver never reaches EAS register().
M2 — batch-anchor abusePASS *pre+post-assert batchAnchor==multisig. *Caveat: checks address-equality, not that the multisig is a contract — operator must point it at a real multisig.
M3 — oracle score ladderPASSrate-bounded (maxDelta/cooldown) + pausable; accepted single-oracle testnet SPOF; no on-chain value sink → 0 on-chain profit. (Mainnet item below.)
M4 — seed-floor farmingPASSfree to mint but the 500bp seed decays to ~0 in ~3 epochs, bots flagged isVerified=false, converts to no on-chain value → ROI ≈ 0.
M5 — ERC8004 ownerOfPASSdeploy probes ownerOf(huge), throws on revert, asserts address(0); registry built to return 0 not revert.
FeeRouterPASSdust→treasury deterministically; gas-capped (30k) fault-isolated payouts (failing recipient → owed+claim, never reverts batch); no retroactive/permissionless redirect; balance≥totalOwed solvency invariant holds; rescue blocked for fee/owed tokens.
Fee-path wiringPASSfail-closed: throws if real-Shyft but PaymentModule/FeeRouter absent; cannot silently succeed; 6 post-asserts.
Fail-closed on chainId 2201PASSblocked both directions: forceMock+2201 throws; env/RPC chainId mismatch killed by preflight before any deploy.
6 other RMT contractsPASSCitationCounters authorizedCaller immutable; RMTToken non-minter blocked; ERC8004 agentId-0 reverts; Domain isolation gated + cross-validated.
Economic attacks (5)PASSsybil-farming, oracle-ladder, seed-floor, FeeRouter dust/grief, fee-evasion — none economically rational on-chain (no value sink).
!

What to fix (centralization — not vulnerabilities)

DO NOW (cheap)  Transfer PaymentModule ownership to the multisig

The red team ran the real deploy and confirmed TrustAnchorStorage_PaymentModule.owner() == deployer — it's never moved to the multisig. Since setPaymentReceiverAddress is onlyOwner, the deployer can redirect all attestation fees in one tx (demonstrated). The FeeRouter goes to the multisig, but the module that feeds it doesn't. Fix: transfer PaymentModule ownership to the multisig in the deploy + post-assert. Acceptable on testnet; close before any real value flows.

MAINNET GATE  Decentralize the oracle + cap initial score

Single oracle operator + maxInitialScore=10000 (no cap) lets a compromised key write any score in one tx. Documented testnet-accepted (S-03). Mainnet needs the oracle committee + a non-trivial initial-score cap — required before any value-bearing consumer reads the score.

MAINNET GATE  Multisig + timelock all owner keys; ops-verify multisig addresses

RMTToken admin (uncapped mint), PageRankOracle multisig, resolver/bridge/registry/FeeRouter/PaymentModule owners → multisig+timelock. Operationally verify STABLE_MULTISIG/STABLE_BATCH_ANCHOR resolve to real multisig contracts (M2 only checks the address).

POLICY DECISION  Zero on-chain economic friction as configured

citationFee=0, registrationFee=0, paymentForAttestation=1 wei — there's no meaningful on-chain cost to citing/registering. Friction today is entirely the off-chain Shyft-anchor governance gate. Not a bug, but if the threat model assumes per-action cost deters spam/Sybil, that's a deliberate decision to make before launch.

Adversary lenses

Deploy + integrity (Claude)
Built a 30-test hardhat attack harness; passed the negative control; attacked all audit invariants + 6 RMT contracts + centralization.
DONE · 0 exploitable
Economic / game-theory (Claude)
Quantified cost-vs-gain for sybil farming, oracle ladder, seed-floor, FeeRouter dust, fee-evasion against real parameters.
DONE · 0 profitable
FeeRouter + core (Codex)
First task aborted; retry confabulated the source (described a pendingBalance/ECDSA-cite() design that doesn't exist; 0 occurrences in real file). Its lone "FAIL" (rescue over-reach) was refuted by canonical source — real rescue() reverts ProtectedToken on configured/owed tokens (FeeRouter.sol:342-347). Excluded. The canonical-source floor caught the hallucination. These targets already passed Codex in AUDIT 3/3 + 3 FeeRouter CODE_REVIEW rounds where Codex caught the only real bugs (now fixed).
CONFABULATED → REFUTED (floor held)
Method. Independent adversaries, break-it (not review) mandate, negative-control floor enforced, only confirmed-exploitable findings count (default refuted), PoC + file:line for any FAIL. Read-only; no tracked files modified. Target: /private/tmp/antilles-integrated-wt @ stable-deploy-integrated 0d8c819e. 166 tests green (136 + 30 red-team) on the deploy/integrity pass.
Verdict. TESTNET GO (zero exploitable, all invariants resist attack). MAINNET CONDITIONAL on the named centralization items — no code defect blocks it. Pairs with the formal AUDIT (3/3 signed) + CODE_REVIEW records.
Next. Operator: transfer PaymentModule ownership → multisig (do-now); then faucet deploy (fund deployer + set STABLE_SHYFT_SECOND_ADMIN + trigger).