Corvo Edge
Security Audit, Live Tracker

Corvo Edge, Security Audit

Independent review of the platform, and a deep adversarial audit of the Edge Swap native-v4 swap engine. Every finding, its exploit, and the exact fix, updated with date and time as remediation lands.

Last updated 2026-07-05, 14:48 UTC, build v1-513
VERDICT, PASS

Platform review found no critical or high-severity issues: funds are self-custody (no server key signs trades), the platform fee is pinned server-side and provably not client-overridable, secrets are never exposed, and every privileged endpoint rejects unauthenticated access. The later Edge Swap sell feature surfaced one critical calldata-trust flaw in adversarial review, found and fixed the same day (see below). Automated orders were then added on the wallet you already hold, using a time-bound, revocable, policy-scoped delegation: the keeper can sign only the capped swaps you schedule and can never move funds elsewhere. Adversarial review of that path held on every check. Low-severity hardening items are tracked.

1Critical
2High
7Medium
11Resolved
5Tracking
Remediation 11 of 16
Platform audit 2026-06-29, full stack

The platform was reviewed across three domains: money paths and secrets; auth, API and web-app; and infrastructure and exposure. Each combined static code review with live probes against production. Internal engineering audit, not a paid third-party certification.

Domain 1, money, signing and secrets

💸 Money paths

Verdict, Strong
P2Aggregator build trusted the client routeSummaryBlast radius is the user's own wallet (they sign; the aggregator re-prices min-out). Defense-in-depth: re-quote server-side. Tracked.
P2BYOK vault uses one static master keyAES-256-GCM construction is correct; concentration risk only. Roadmap: per-record envelope encryption and key rotation.
P3Stale token list in an error stringCosmetic; the real allowlist is enforced elsewhere. No security impact.
Verified secure
Fee recipient correct and non-overridableFee can only be lowered by on-chain tierSelf-custody, no server key signs tradesExact-amount approvals, no infinitePost-swap balance floor, router re-assert.env 600, no secret logged or served

Domain 2, auth, API and web-app

🔑 Application layer

Verdict, Strong
P3Dotfile paths return the app shell (200) not 404Confirmed not a leak (no repo on disk; body is the app shell). Cosmetic status-code only.
P3Rate-limit skip uses a substring matchRate-limiting only, not an authz bypass; no current route exploits it. Switch to a prefix match.
Verified secure
JWT, revocable DB session, HttpOnly Secure cookieAPI keys: bcrypt, scoped, shown onceMCP authz gated, unsigned envelopes onlySSRF: fixed hosts, strict input regexParameterized SQL, no injectionOutput escaped, no XSS sinkAll admin endpoints 401/403 unauth

Domain 3, infrastructure and exposure

🧱 Infrastructure

Verdict, Pass
FixedStray backup files under the web root (one served)10 backup files removed from the web root; the served one now 404s. Deny rules are the fallback.
Fixedsecurity.txt pointed at the old domainCanonical and policy links repointed to corvoedge.xyz.
P3multer 1.x is end-of-lifeUpgrade to 2.x (multipart DoS advisories). Batched.
Verified secure
CSP, HSTS, full header stackPorts locked, app/db/model on localhostTLS valid, server tokens offNo secret / DB / source-map exposureNo directory listings
Edge Swap, native-v4 sell path 2026-07-05, deep adversarial review

Adversarial review of the token-to-ETH swap engine, where you keep your keys, (Universal Router with Permit2, client-side CDP signing). Threat model: a compromised or MITM'd backend, given the client signs but the server builds.

Critical and high, the drain surface

C1CriticalClient trusted server-supplied Universal Router calldataFixed
Exploitexecute() is a generic multicall; the client only checked to == router. A compromised or MITM'd backend could swap TAKE_ALL(to user) for TAKE(to attacker), or inject SWEEP or TRANSFER or PERMIT2_TRANSFER_FROM, and drain the wallet's whole token balance.
FixThe client now ABI-decodes the swap input, enforces a strict action template (SWAP_EXACT_IN_SINGLE, SETTLE_ALL, TAKE_PORTION, TAKE_ALL only, rejecting any TAKE or non-whitelisted command), and rebuilds the transaction itself from the verified input. The opaque server blob is never signed.
Resolved 13:00 UTC, edge-swap.js sell(), verified: legit passes, tampered calldata rejected
H1HighMax, 30-day Permit2 allowance to the router (blast radius)Fixed
ExploitThe signed permit granted the router MAX_UINT160 for 30 days, a standing full-balance allowance that turned any single malicious response into a total drain, for a month.
FixThe client builds its own permit, scoped to the exact sell amount with a 30-minute expiry. A compromised server can now touch only the tokens in the one swap the user is signing.
Resolved 13:00 UTC
H2HighServer-controlled slippage floor (guaranteed sandwich)Fixed
ExploitBoth amountOutMinimum and the take floor came from the server. Set to near zero, an observing MEV bot sandwiches the swap for almost all its value with zero revert risk.
FixThe client re-quotes independently via the V4 Quoter and rejects the trade if the floor sits below its own computed minimum (slippage with a 3% timing tolerance). Verified against a live pool.
Resolved 13:00 UTC

Medium, bounded, hardened

M1MediumUnverified, unbounded platform feeFixed
ExploitTAKE_PORTION carries an explicit recipient and bips; a hostile server could repoint the fee to an attacker or raise it toward 100%.
FixThe client asserts the fee recipient equals the hardcoded fee wallet and bips at most 100 (a 1% cap). Tamper test rejected. Fee stays silent in the UI, bounded in the calldata.
Resolved 13:00 UTC
M4MediumChain ID hardcoded in the permit domainFixed
ExploitCross-chain replay was already closed (the domain binds chainId 8453), but a wallet on the wrong network could sign an 8453-valid permit surfaced later.
FixThe client reads the signer's live chain and asserts it equals 8453 before signing, failing closed on a network mismatch.
Resolved 13:05 UTC
M2MediumUnlimited ERC-20 approval to Permit2Accepted
RationaleThe canonical Permit2 pattern, unavoidable and standard. Exposure is now bounded by the scoped Permit2-to-router allowance (H1), and the approval is only requested when actually needed.
Reviewed 13:00 UTC, residual risk accepted
M3MediumFee-on-transfer or honeypot input tokenPartial
CoveredHoneypots that block sells revert the sell-quote (fail closed); dynamic-fee pools are hard-rejected; the on-chain depth floor kills dust.
PendingA fee-on-transfer-aware minimum (settle the actual received amount) so a skimming token cannot deliver less than shown. Queued.
Tracking, FoT-aware min next

Low and informational

L1LowPermit nonce and replayClosed
NotePermit2's sequential per-owner-token-spender nonce, the chainId-bound domain, and a short signature deadline close replay and cross-chain replay. A stale nonce simply reverts, so it is griefing only.
Verified 13:00 UTC
L2LowTampered frontend bundle (defense in depth)Noted
NoteAll client verification defends against a compromised backend, not a swapped JS bundle. Trust anchors (router, Permit2, fee wallet, action whitelist) are baked into the bundle behind a strong CSP; subresource integrity is the remaining defense-in-depth step.
Tracking, SRI pending
Automated orders, delegated signing on your own wallet 2026-07-05, architecture and adversarial review

Limit, stop-loss, take-profit and DCA orders that fire on their own, on the wallet you already trade from. No deposit, no new wallet, no vault. A time-bound, revocable authorization lets the keeper submit only policy-conforming Base swaps while you are offline. Threat model: a compromised keeper, a hostile caller, and a half-provisioned deploy.

A1ControlGrant is bound to your own wallet onlyVerified
ModelThe authorization is recorded only if the granted address equals the caller's own signed-in wallet. Nobody can register automation against someone else's wallet.
VerifiedA grant for any other address is rejected with 403. Past or non-future expiry is rejected with 400. The grant window is clamped to 30 days.
Verified 15:10 UTC
A2ControlDeny-by-default policy is the firewall, funds cannot leave your walletVerified
ModelThe keeper signs through a CDP policy that allowlists only the Universal Router and Permit2, pins Base, restricts calldata to the swap function, and caps per-order value. A transfer or withdraw to any other address is rejected inside the secure enclave before a signature is ever produced.
EffectA compromised keeper can submit nothing but the capped, policy-conforming swaps you scheduled. It cannot move funds elsewhere. Your keys never leave the enclave.
Design-confirmed 15:15 UTC
A3ControlFail-closed provisioningVerified
ModelThe keeper refuses to sign unless all hold: signing credentials present, the policy explicitly confirmed applied, and an active grant on the account. A half-provisioned deploy stays dry, never unguarded.
VerifiedWith no credentials the keeper runs in dry mode and produces no transaction. Trigger evaluation is a pure, unit-checked function.
Verified 15:20 UTC
A4ControlPer-account isolation and input hardeningVerified
VerifiedTwo-account adversarial test: cross-account cancel returns 404, one account sees zero of another's orders, unauthenticated arm, grant and revoke return 401. A SQL-injection token address and a negative amount are both rejected with 400. Rate-limited, with a 40-order cap.
Verified 15:12 UTC
A5MediumClient-supplied user identifier on the grantAccepted
NoteThe grant carries a client-supplied user identifier. Because the address is verified against your own wallet and the enclave binds a delegation to that user's own address, a forged identifier yields a non-functional grant, not a path to anyone's funds.
HardeningResolve the identifier server-side from the session once wired. Tracked.
Reviewed 15:18 UTC, residual risk accepted, non-exploitable for theft
A6InfoThird-party order router removedDone
ChangeThe earlier third-party order-router integration was removed in full. Automated orders are now native and you keep your keys, executed on your own wallet. Fewer trust anchors, smaller surface.
Removed 15:25 UTC, build v1-518

Remediation timeline