Security
Audit
Self-audit findings, test results, and external audit status.
Evidence and its scope
Tests
Implementation checks
Self-audit
Historical scope only
Security
Self-audit findings, test results, and external audit status.
Evidence and its scope
Tests
Implementation checks
Self-audit
Historical scope only
External review
Not complete
The historical findings below do not cover CreditTopUp, the finalized-payment settlement worker, or the topup database migration. Independent review of the new payment flow is pending.
AgentPass has an internal self-audit of the legacy contracts. The single-membership upgrade and new credit ledger are not covered by that historical report. An independent external audit is not complete.
| Item | Status |
|---|---|
| Legacy self-audit | Complete for the pre-upgrade scope |
| CreditTopUp and settlement | Implementation tests and testnet payment checks complete; independent review pending |
| Single-membership upgrade | Implementation tests and testnet verification complete; independent review pending |
| External audit | Not started |
| Mainnet | Not deployed |
The self-audit was written by the team that wrote the contracts. It is not independent and does not replace an external review.
AgentPassPassRendererRewardDistributorTaxSplitterAirdropVestingAgentPassProxyReentrancyGuardUpgradeableOut of scope:
The single-membership verification on 3 November recorded 243 passing tests: 203 Solidity and 40 Node.js tests, with 5 fork tests skipped in the default run. Storage validation passed for AgentPass to AgentPassSingle. A local testnet fork rehearsal and the existing-proxy testnet upgrade preserved the original NFT, owner, weight, and reward balance. Two further testnet mints confirmed repeated minting and distinct $5 credit grants. These are historical results, not an external security audit.
The 5 November verification recorded 254 passing contract-suite tests: 214 Solidity and 40 Node.js tests. Five historical RPC fork tests were skipped in the default run. Credit ledger, inference, finalized-payment settlement, and local end-to-end checks also passed in the topup release record.
The active testnet deployment was verified with BNB and mock USDT payments, exact permanent credit grants, and replay/restart checks. Migration retained existing balances and legacy claim records. The repository evidence is in docs/28-onchain-topups.md and docs/30-testnet-treasury-redeployment.md. These checks do not extend the historical self-audit's coverage or replace independent review.
| ID | Severity | Title |
|---|---|---|
| H-01 | High, conditional | Airdrop token transfer tax can under-deliver allocations |
| M-01 | Medium | Just-in-time mint dilutes reward deposits |
| M-02 | Medium | RewardDistributor trusts pass-supplied weights |
| M-03 | Medium | Upgrade validation covers only two of four UUPS contracts |
| M-04 | Medium | Keeper-controlled slippage and deadline can be set loosely |
| M-05 | Medium | Airdrop root can be zero or missing when start is set |
| L-01 | Low | Oracle round completeness is not checked |
| L-02 | Low | Future oracle timestamp can panic the mint |
| L-03 | Low | Reward deposit assumes an exact USDT transfer |
| L-04 | Low | unclaimed() can underflow if accounting breaks |
The airdrop token is a four.meme TaxToken. If it taxes ordinary transfers from AirdropVesting, users receive less than their allocation while the contract records the gross amount.
This must be verified before mainnet. Possible fixes:
A wallet can mint just before a reward deposit and capture a share of that deposit. Existing holders are diluted.
Possible fixes:
The Hardhat validation covers AgentPass and RewardDistributor. TaxSplitter and AirdropVesting are covered by Foundry tests but not by the automated validation script.
The external audit is not started. The audit package includes:
The full self-audit report is available to auditors on request.
Do not deploy to mainnet until:
| L-05 | Low | PassRenderer metadata call is gas-heavy |
| L-06 | Low | Handle length is not bounded by AgentPass |
| L-07 | Low | AirdropVesting.initialize allows a past start |
| L-08 | Low | Token existence is not checked in several views |
| I-01 | Informational | _mint is used instead of _safeMint |
| I-02 | Informational | Uppercase handles are dropped by the renderer |
| I-03 | Informational | pending() returns only the stored pending amount |
| I-04 | Informational | contractURI() uses string.concat for one string |
| I-05 | Informational | Zero allocations remain in the Merkle tree |
| I-06 | Informational | TaxSplitter sweeps the entire USDT balance |
| I-07 | Informational | Initialize functions do not reject self or non-contract addresses |
Foundry: 192 passed, 0 failed, 5 skipped (197 total)
Fork: 5 passed with Anvil
Hardhat: 233 passing, 5 skipped
Upgrade validation: AgentPass and RewardDistributor