Security
CogmemAi holds what your Ai remembers. AgentWallet moves money on behalf of software. Both products are built on the assumption that a prompt-injected agent, a hostile endpoint or a careless operator will test every boundary, and both publish what they guarantee, what they do not, and every issue that has been reported and fixed. This page gathers that material in one place, together with the way to reach us.
Report a Vulnerability
Please do not open a public issue for anything exploitable. Use one of the private channels below, and we ask that details stay private until a fix has shipped.
Write to [email protected] with the product, the version, the steps to reproduce and the impact you observed. Encrypted mail is welcome; ask for a key in your first message.
Private GitHub report
For agentwallet-mcp, a private vulnerability report can be filed at github.com/hifriendbot/agentwallet-mcp/security. The report is visible only to the maintainers until a fix is published.
Response and disclosure
We answer within three business days. A confirmed issue is fixed, released and recorded in the disclosure history below and in the changelog. Reporters are credited unless they ask to remain unnamed.
Bounty for AgentWallet. Confirmed findings in agentwallet-mcp and the hosted AgentWallet API are paid in USDC on Base according to the published tiers: $50 for low, $150 for medium, and $500 for high or critical severity. Whether a report qualifies, and at which tier, is the maintainer's decision. Two researchers were paid through this channel in 2026. The policy of record is SECURITY.md in the repository; where this page and that file differ, the file governs. A machine-readable contact is published at /.well-known/security.txt.
What We Protect, and How
The claims below are taken from each product's published documentation. Each one describes a control that exists in the shipped code, not an aspiration.
CogmemAi
Memories encrypted at rest
Memories are encrypted at rest with quantum-resistant encryption in cloud mode and in local mode. Encryption is on by default and needs no configuration.
API keys stored as hashes
A CogmemAi API key is shown once, at the moment it is generated. The server stores only a SHA-256 hash of the key and a four-character hint, so a copy of the database does not yield working keys.
OAuth 2.1 with PKCE
The remote MCP endpoint speaks OAuth 2.1. Clients discover the authorization server, register, send the user to a consent page and receive a token through the authorization code flow with PKCE (S256), which is mandatory. API keys continue to work for clients that prefer them.
Guard runs before the action
Rules saved in memory are enforced before an action happens: a shell command, a message, a purchase or a change. In a coding tool Guard runs as hooks; everywhere else the Ai you run asks with one call before it acts and one review after it finishes.
Three storage modes
Cloud, local and hybrid. In local mode the data stays on your machine and the free API key acts only as a license key. Which mode is in use is a setup choice you make, and you can change it.
Honest about failure
When an upstream firewall, CDN or proxy intercepts a request, the client reports it loudly instead of returning an empty result that looks like success. Guard itself fails open: if anything inside it breaks, your command runs untouched and the failure is logged.
AgentWallet
Self-custody option
Run local mode and the key never leaves your machine. An operation with no matching local key is refused, never routed to the hosted signer. The local-mode tests run with the hosted API pointed at a closed port; if any path reached a server, the tests would fail.
Hosted keys encrypted at rest
In hosted mode, private keys are encrypted before storage, decrypted only during signing, and zeroed from memory immediately afterwards. You can export a hosted key and move to self-custody at any time.
Spend policy and hash-chained ledger
One JSON file sets rolling daily, monthly and lifetime budgets, per-host ceilings, host and recipient allow and deny lists, chain and asset lists, and a human-approval threshold. Budgets are enforced from an append-only, hash-chained ledger under an exclusive lock, so two concurrent calls cannot both fit the last dollar.
EIP-3009 authorizations
An x402 payment under the exact scheme is a signed TransferWithAuthorization for exactly the amount asked. The payer broadcasts nothing and pays no gas; the endpoint's facilitator settles it on chain. A valid authorization is re-sent rather than re-signed, so a retry cannot pay twice.
SSRF guard on every outbound URL
Paid URLs must be HTTPS. Every hop is resolved once, checked against private address ranges and pinned to the validated addresses. At most three redirects are followed, a cross-origin hop becomes a body-less GET, caller credentials are dropped, and response bodies are capped at 8 MB.
Token caps that fail closed
Amounts are priced at trusted decimals (the registry, then the contract), never at decimals an endpoint declares. On Solana the recipient must be a system-owned wallet, never a mint, a token account or a program, and a caller's decimals hint may only confirm the mint's own value. Calldata the guard cannot price is refused rather than allowed uncapped.
What the caps cannot defend: the RPC endpoints and the AgentWallet API host are chosen by the operator and trusted, allowances granted before a cap was set are not bounded by it, and gas is outside the native value cap. These boundaries are stated in full under What the code guarantees. Releases are published with npm provenance, nothing in the package runs an install script, and pinning an exact version is the recommended deployment.
Fixed Disclosures
Every AgentWallet report that led to a change, from outside researchers and from our own adversarial audits, with the release that carried the fix. Rows marked Duplicate were already fixed when they arrived and are listed for completeness. The source of this table is SECURITY.md in the repository; each row there carries the full description and the regression test that covers it.
| Date | Severity | Summary | Fixed in |
|---|---|---|---|
| 2026-10-25 | Low | Reported privately: loadPolicy found the policy file's directory by stripping everything after the last slash, so a bare relative filename (AGENTWALLET_POLICY=policy.json, no slash) was left whole and became the... | v1.14.6 |
| 2026-10-24 | Medium | Reported privately (twice, by the same researcher): the policy matcher compared the hostname as the URL parser returned it, and Node keeps the DNS root label's trailing dot (and decodes a percent-encoded one into it)... | v1.14.5 |
| 2026-10-24 | Low | Reported privately: in hosted mode the policy priced an SPL send at the caller's token_decimals whenever one was given, reading the mint only when the hint was absent, so 1,000 USDC sent with token_decimals: 18 was... | v1.14.5 |
| 2026-10-23 | High | Reported privately: once a call's calldata matched a classified layout (an ERC-20 transfer, an approval), the native value the call carried was dropped before the policy ran, so in local mode a transfer() carrying 1 ETH... | v1.14.4 |
| 2026-10-23 | Duplicate | Reported privately, the same day and after the report above: the same carried-value gap, adding that with recipients.allow set the contract keeping the value was never checked, only the address inside the calldata | Already fixed |
| 2026-10-16 | Low | Reported privately: in local mode, every refused sign_transaction consumed the rolling budget for good. | v1.14.3 |
| 2026-10-14 | High | Reported privately: the 1.14.0 spend policy decoded only transfer calldata, so an ERC-20 approve (including approve_token with "max" and approve_permit2 with no amount) fell through as a plain contract call... | v1.14.1 |
| 2026-10-14 | High | Reported privately: in hosted mode the spend policy was enforced only on /wallets/{id}/send; sign_transaction posts to /wallets/{id}/sign and returned a signed, broadcast-ready transaction with no policy check, no... | v1.14.2 |
| 2026-10-14 | Medium | Reported privately: the 1.14.0 ledger was read once at startup and never re-read, with no lock across the check-and-append step, so two live agentwallet-mcp processes sharing one ledger file (two MCP... | v1.14.2 |
| 2026-10-05 | Medium | Internal adversarial audit, round 8 (1.13.15): the "one live authorization per resource" guard was keyed on the chain, so a paywall rotating the chain per answer harvested one cap-sized nonce per registry chain for a... | v1.13.16 |
| 2026-10-05 | Low | Internal adversarial audit, round 8 (1.13.15): an MCP cancellation (notifications/cancelled) of an in-flight pay_x402 was ignored; the handler went on to sign and deliver the payment and the client never saw a result | v1.13.16 |
| 2026-10-05 | Low | Internal adversarial audit, round 8 (1.13.15): the hosted broadcast-transfer branch of pay_x402 posted /wallets/{id}/send without the skip header, so a metered 402 from the API host was auto-paid inside the call and the... | v1.13.16 |
| 2026-10-05 | Low | Internal adversarial audit, round 8 (1.13.15): a v2 requirement with megabytes of junk in outputSchema or extensions was echoed whole into PAYMENT-SIGNATURE (5 MB header per paid retry, kept in the cache for the... | v1.13.16 |
| 2026-10-04 | High | Internal adversarial audit, round 3, server side (hosted API 1.7.2, deployed 2026-10-04): the server's per-transaction token cap knew only transfer, approve and transferFrom, so increaseAllowance, Permit2.approve... | v1.13.8 |
| 2026-10-04 | High | Internal adversarial audit, round 5 (1.13.12), network edge: the RPC-secret redaction ran a quadratic regex over the node's whole error text, so a 160 KB error page froze the single-threaded server for 14 s and a 5 MB... | v1.13.12 |
| 2026-10-04 | High | Internal adversarial audit, round 4 (1.13.11), local EVM path: nothing bounded the fee of a locally signed transaction; a node answering a 47,000 gwei priority fee or a 30M gas estimate took the whole native balance as... | v1.13.11 |
| 2026-10-04 | High | Internal adversarial audit, round 4 (1.13.10), local Solana path: the SPL token cap read the mint's decimals through a cached call and the instruction through an uncached one, so an RPC that answered 6 to one read and... | v1.13.10 |
| 2026-10-04 | High | Internal adversarial audit, round 3 (1.13.8), hosted trust boundary: with AGENTWALLET_WALLET_ID set, a 402 from the API host on ANY call (list_wallets, get_chains, get_token_info's three internal reads) was paid... | v1.13.8 |
| 2026-10-04 | Medium | Reported privately: pay_x402 learned which origin finally answered from the x-agw-final-url response header, and safeFetch copied every server header through before appending its own, so a server reached through a... | v1.13.4 |
| 2026-10-04 | Medium | Internal adversarial audit (1.13.5): in local mode with hosted credentials also configured, a 402 from the API host on any call that falls through to it (usage, chains, paywall reads) ran the internal auto-pay, which... | v1.13.5 |
| 2026-10-04 | Medium | Internal adversarial audit (1.13.5): the local token cap's decimals() probe trusted viem's revert classification, which maps JSON-RPC error -32603 and an empty envelope to "the contract reverted", so a transient node... | v1.13.5 |
| 2026-10-04 | Medium | Internal adversarial audit (1.13.5): transfer_token on a Solana mint outside the registry scaled the amount by the caller's decimals and then wrote the mint's real decimals into the instruction, so the on-chain check... | v1.13.5 |
| 2026-10-04 | Medium | Internal adversarial audit (1.13.5): a server could shrink the signed authorization window to seconds, vary an amount's leading zeros, or answer parallel calls, and each retry signed a fresh nonce it could also settle | v1.13.5 |
| 2026-10-04 | Medium | Internal adversarial audit, round 6 (1.13.13), prompt-injection arrival across all 34 tools: a hostile API host's 402 on the auto-pay path produced a 4 MB error built from raw accepts entries (tool errors had no size... | v1.13.13 |
| 2026-10-04 | Medium | Internal adversarial audit, round 4 (1.13.10): a leading space in AGENTWALLET_API_URL defeated the https-only check (the regex saw the space, fetch did not) and Basic credentials went out in plaintext; unknown tool... | v1.13.10 |
| 2026-10-04 | Medium | Internal adversarial audit, round 3 (1.13.8): when the first of N parallel pay_x402 calls for one purchase failed, every waiter proceeded at once and signed its own nonce (7 nonces from 8 calls); a paywall that varied... | v1.13.8 |
| 2026-10-04 | Medium | Internal adversarial audit, round 2, server side (hosted API 1.7.1): one DELETE with a leaked API key destroyed a wallet key; the approval email's amount and token name were the agent's own text; the emailed approve... | v1.13.7 |
| 2026-10-04 | Medium | Internal adversarial audit, round 2 (1.13.6): an ERC-721 or ERC-1155 collection declines decimals() and so counted as "not a token" to the cap, which let setApprovalForAll(attacker, true) and NFT transfers through... | v1.13.6 |
| 2026-10-04 | Low | Internal adversarial audit (1.13.5): every EVM RPC failure returned viem's message, which carries the RPC URL with its API key, to the agent (the 1.13.0 redaction covered wallet_mode only); an out-of-range private key... | v1.13.5 |
| 2026-10-04 | Low | Internal adversarial audit (1.13.5): the Solana recipient guard accepted any account not owned by a token program, including program-data, buffer and lookup-table accounts that nothing can sign for; a plain account... | v1.13.5 |
| 2026-10-04 | Low | Internal adversarial audit (1.13.5): Permit2 was recognised at one address, so a chain with a different deployment (zkSync Era) got no Permit2 guard; a whitespace-only cap value meant "no cap"... | v1.13.5 |
| 2026-10-04 | Low | Internal adversarial audit, round 4 (1.13.10), startup and docs: AGENTWALLET_MAX_AUTOPAY_PER_HOUR was unvalidated (blank meant 0, garbage meant 20); a misspelled AGENTWALLET_* name ran uncapped without a warning... | v1.13.10 |
| 2026-10-04 | Low | Internal adversarial audit, round 3 (1.13.9), Permit2 upto and EIP-712 signing: for a token outside the domain registry the "exact" signer read name()/version() through the 64-character display sanitiser instead of the... | v1.13.9 |
| 2026-10-04 | Low | Internal adversarial audit, round 2 (1.13.6): payment_made trusted a server-sent settlement header even on a 402 or 500, and the server's claimed transaction hash was shown as tx_hash; a legacy-shaped 402 from any host... | v1.13.6 |
| 2026-10-04 | Low | Reported privately: the authorization-reuse key was built from origin and path without the query string, so two resources at the same path with different queries shared one signature and the second was reported paid... | v1.13.4 |
| 2026-10-04 | Informational | Internal adversarial audit (1.13.5): several refusal messages told the agent to raise the operator's caps itself; the pay_x402 description still said upto is refused and that max_payment can raise the cap; untrusted... | v1.13.5 |
| 2026-10-04 | Informational | Internal adversarial audit, round 2 (1.13.6): USDT, DAI and USDbC in the registry do not implement EIP-3009 (checked on chain), so an "exact" payment in them signed a dead authorization; Polygon USDT now reports as... | v1.13.6 |
| 2026-10-02 | Low | Reported privately: the Solana recipient guard refused programs and token accounts but used a length gate, so an 82-byte token mint passed as a wallet and an SPL send to it landed in a token account owned by the mint... | v1.13.2 |
| 2026-10-02 | Low | Reported privately: in local mode with hosted credentials also configured, pay_x402 accepted an approval_id from the hosted account, but the local signer never reports back, so the approval was never marked used and... | v1.13.2 |
| 2026-10-02 | Informational | Reported privately: when an SPL send has to create the recipient's token account, the rent checked against AGENTWALLET_MAX_TX_SOL was computed for the classic 165-byte account, while a Token-2022 account is 170 to 195... | v1.13.3 |
| 2026-09-28 | Medium | Reported privately: in local mode increaseAllowance was checked on the increment alone, so repeated compliant calls could leave a spender's standing allowance above AGENTWALLET_MAX_TX_TOKEN | v1.13.1 |
| 2026-09-28 | Low | Reported privately: the internal auto-pay path (a 402 from the configured AgentWallet API host, not pay_x402) took the first offer without checking its scheme, so an upto maximum from that host would have been paid... | v1.13.1 |
| 2026-09-28 | Informational | Reported privately: for a token outside the registry, a compromised RPC answering a false decimals() scales both the signed amount and the token cap by the same factor. | v1.13.1 |
| 2026-09-28 | Duplicate | Reported privately against 1.12.5: the legacy payTo calldata shift already fixed in 1.13.0 (row above), reported after that release | Already fixed |
| 2026-09-27 | High | Internal audit (1.13.0): the x402 cap was "1 unit of whatever asset the endpoint named", so a hostile 402 asking for native ETH was measured against a 1 ETH cap and the asset label shown to the agent (and in the... | v1.13.0 |
| 2026-09-27 | Medium | Internal audit (1.13.0): authorization validity followed the endpoint's maxTimeoutSeconds with no ceiling and every retry signed a fresh nonce (a withholding server could harvest one cap-sized authorization per retry)... | v1.13.0 |
| 2026-09-27 | Low | Internal audit (1.13.0): SPL sends could burn tokens into a token account or program address and paid recipient-account rent the SOL cap never saw; one Solana or EVM RPC URL served every chain id unchecked; the SPL... | v1.13.0 |
| 2026-09-27 | Low | With AGENTWALLET_MAX_TX_TOKEN set in local mode, wrap_eth and unwrap_eth were refused by the token cap (WETH deposit() / withdraw(uint256) are unpriced calldata to a token contract) and the only way to restore them was... | v1.12.6 |
| 2026-09-26 | Medium | Token cap let unpriced calldata through when the target's decimals() answered outside 0..36: the probe reported "absurd answer" and "no answer" with the same null, and only "no answer" was meant to pass | v1.12.5 |
| 2026-08-19 | High (functional) | exact scheme sent a broadcast transfer instead of an EIP-3009 authorization; standard servers rejected every payment | v1.11.0 |
| 2026-08-12 | Medium | upto scheme settled as a full upfront transfer (overcharge relative to usage) | v1.11.0 |
| 2026-07-26 | Medium | AgentWallet API keys were WordPress application passwords usable on any REST route, and key-management routes accepted them | Hosted API |
| 2026-07-26 | Low | Daily spending limit could be enforced but never set | Hosted API |
| 2026-06-27 | High | pay_x402 cap could be bypassed when max_payment was omitted (attacker-controlled maxAmountRequired reached the transfer) | v1.8.0 |
54 rows. Hover a version for the full fix description. CogmemAi has no disclosed vulnerabilities on record at this time; a report would be handled through the same channels and listed here.
See the Record
Every release is dated and summarized on the changelog, and the live health of each component is on the status page.
