# Aere Network: adversarial-review fixes (pre-deploy hardening) Source review: `aerenew/docs/AERE-SECURITY-REVIEW-NEW-CONTRACTS.md` Repo: `aerenew/contracts` (solc 0.8.23, OpenZeppelin v4.9.x). All contracts founder-gated, not deployed. Guard pattern for L1 copied from `contracts/pqfinality/AereFinalityCertificateVerifier.sol` (`gateway.code.length == 0` revert). ## Per-finding status ### M1 (MEDIUM) FIXED, with proof File: `contracts/erc8004/AereReputationRegistry8004.sol` - Made the adapter `Ownable` (OZ v4, `@openzeppelin/contracts/access/Ownable.sol`, matching the repo). - Added `mapping(address => bool) public isAuthorizedFeedbackAuthor`, owner functions `addFeedbackAuthor` / `removeFeedbackAuthor` (with `FeedbackAuthorSet` event and a zero-address guard on add), and a new error `NotAuthorizedFeedbackAuthor(address)`. - Gated `giveFeedback`: first line now reverts `NotAuthorizedFeedbackAuthor` unless `isAuthorizedFeedbackAuthor[msg.sender]`. The rest of the flow (agent-registered, delta clamp, adapter-is-attestor) is unchanged. - Design choice (documented in NatSpec): owner-curated author allowlist, mirroring the live AereAIReputation curated-attestor model. Scope is authorization-only: the owner cannot set a reputation value, cannot exceed the `{-1,0,+1}` delta clamp every author is held to, and moves no funds. No re-entrancy, no fund/reputation-value backdoor. Read path (`getScore`, `getStats`, `liveKeyOf`, `canWriteThrough`) untouched. ### L1 (LOW) FIXED (x3), with proof Added the sibling's codeless-gateway guard to each verify path. New error `VerifierHasNoCode()` in each. - `contracts/mpc/AerePQAggregateVerifier.sol` constructor: reverts if `gateway.code.length == 0` (after the existing `ZeroGateway` check). - `contracts/depin/AereComputeMarketV3.sol` constructor: reverts if `zkVerifier.code.length == 0` (after the existing `ZeroAddress` check). - `contracts/compliance/AereBitstringStatusList.sol` constructor: reverts if `nonRevocationVerifier_ != address(0) && nonRevocationVerifier_.code.length == 0`. The zero address is still allowed (keeps the zk non-revocation path fail-closed OFF until configured), which preserves existing behavior. Verifier is immutable, so the constructor is the correct place. ### L2 (LOW) FIXED, with proof File: `contracts/agentic/AereVectorStore.sol` - Bound each paid-query receipt to an intended provider. Added `address provider` to the `QueryReceipt` struct. - `paidQuery` now takes `address provider` (validated non-zero via existing `ZeroAddress`) and records it in the receipt. Signature is now `paidQuery(storeId, queryHash, provider, agentId, amount, nonce, deadline, authSig)`. The settlement/forwarding flow (AERE402 rail, fee to sink, delta-measured forward to recipient) is unchanged; `receiptId` formula unchanged. - `attestRetrieval` priced branch now reverts new error `NotReceiptProvider()` unless `msg.sender == receipt.provider`, so a third party (or the payer) cannot front-run the honest provider and burn the receipt with a junk resultRoot. `getReceipt` view extended to also return `provider`. ### L3 (LOW) DOCUMENTED (accepted risk), not code-changed File: `contracts/erc8004/AereAP2MandateVerifier.sol` - Chose DOCUMENT over CODE-CHANGE, per the task's guidance, because the two candidate code fixes are unsuitable: (a) a per-authorization nonce would break the intended standing-mandate ("sign once, spend repeatedly up to the cap") semantics that the design and tests rely on; (b) "bind consumption to the executor" is already the built-in `SETTLEMENT_EXECUTOR` gate. - Strengthened the contract-level and `authorizeSpend` NatSpec: the open accounting path (`SETTLEMENT_EXECUTOR == address(0)`) is verification/test-only and MUST NOT be used in production; production MUST set `SETTLEMENT_EXECUTOR` to the AERE402 facilitator so a mandate's cap is only ever consumed alongside a real settlement. No funds at risk (this contract holds none); the vector is cap-exhaustion griefing only. - The existing test "enforces the settlement-executor gate when one is configured" already proves the mitigation works (a non-executor is rejected, the configured executor succeeds). No new test needed. ## Tests added / changed - `test/erc8004-adapters.test.js`: `deployRep` now authorizes `other` as a feedback author (both branches). Two pre-existing tests that relied on the ungated `giveFeedback` were updated to call as the authorized `other` (legitimate behavior change from the M1 gate). Added new test "gates giveFeedback to owner-authorized feedback authors (M1)": unauthorized caller reverts `NotAuthorizedFeedbackAuthor` and writes nothing, owner authorizes -> same call succeeds and moves the live score to 10, owner revokes -> re-blocked, and only the owner may manage the allowlist. - `test/AerePQAggregate.test.js`: added "rejects a code-less SP1 gateway at construction (L1 fail-open guard)" (EOA gateway reverts `VerifierHasNoCode`, zero reverts `ZeroGateway`, real mock deploys). - `test/AereComputeMarketV3.test.js`: added "construction guards" > "rejects a code-less ZK verifier at construction (L1)" (EOA reverts `VerifierHasNoCode`, zero reverts `ZeroAddress`, real mock deploys). - `test/aere-pq-screen.test.js`: added "rejects a non-zero code-less non-revocation verifier at construction, but allows zero (L1)" (EOA reverts `VerifierHasNoCode`; zero deploys and `nonRevocationConfigured()==false`; real mock deploys). - `test/aere-vector-store.test.js`: the two `paidQuery` calls updated to pass `provider.address`; the paid-query test extended to assert the receipt is bound to the provider and that a third party (`operator`) and even the payer (`consumer`) are rejected `NotReceiptProvider` with the receipt left unconsumed, then the bound provider consumes it successfully (L2 proof). ## Real re-run results (npx hardhat test , from aerenew/contracts) - test/erc8004-adapters.test.js .... 19 passing - test/aere-vector-store.test.js ... 8 passing - test/AerePQAggregate.test.js ..... 18 passing - test/AereComputeMarketV3.test.js . 14 passing - test/aere-pq-screen.test.js ...... 13 passing `npx hardhat compile`: green (compiled successfully, then "Nothing to compile" on re-run). ## Notes - No contracts outside the findings were touched. No existing guard was weakened. The L1 zero-address behavior for AereBitstringStatusList was intentionally preserved. Prose contains no em-dashes or "--".