Ethereum contracts deployedTransactions may use real assets. Primary-market minting and instant redemption are KYC-gated; deployment does not mean every product or entry path is open. Review the legal and risk disclosures.

Pre-mainnet campaign

Internal review. This is an internal engineering review of source, not an independent external audit, and it does not by itself authorize a production launch. It reviews the source at the baseline below, which is not necessarily identical to the code deployed on any network. Forest Road Vault is live on Ethereum mainnet; its Solana curator vault remains on devnet and BSC has its own deployment status. An open finding applies only to the product, version and deployment state named by this review. Each review's scope bounds what its clean result is worth. Nothing here is a securities-law representation; token characterization is a matter for counsel.

Scope
The whole codebase, contracts, deployment, validation and QA scripts, invariant harnesses, the frontend, and the governing documents, assessed against both a Sepolia redeploy and mainnet readiness.
Method
A manual pre-mainnet review merged with an adversarial red-team fleet whose findings were each put to a refuter panel, then a 24-lens full-codebase register with executable proof-of-concept reproduction, then two go/no-go re-audits of the resulting fix diff.
Internal report
audit-reports/CONSOLIDATED_PRE_MAINNET_AUDIT_2026-07-20.md, PRE_MAINNET_SECURITY_REVIEW_2026-07-20.md, FULL_CODEBASE_AUDIT_2026-07-21.md, FINAL_FIX_AUDIT_2026-07-22.md, REAUDIT_H5_DELTA_2026-07-22.md

Findings and remediation history

  • C-1HighRemediated

    Queue settlement could burn an entire queued position for exactly zero assets

    Filed Critical, reproduced seven times. Under a fully-marked unrealized impairment the conservative NAV clamp could price a queued position at zero, and settlement burned it anyway. This was the Round 2 sub-wei dust item escalated: the conservative-NAV change destroyed the premise that made it immaterial, and its original recommendation had never been implemented. Confirmed no longer reproducing in the 22 July re-audit.

  • H-1HighRemediated

    Treasury-directed funding plus permissionless reconciliation inflated backing

    Reproduced with 1,500,000 units of unbacked supply measured. Deployment could name the treasury as its own funding recipient, and the then-bidirectional reserve reconciliation converted that into backing. Confirmed no longer reproducing; the reconciliation primitive is now monotone-downward only.

  • H-2HighRemediated

    Partial recovery followed by write-off stranded the impairment pool permanently

    Reproduced three times, with no reachable terminal state. Confirmed no longer reproducing: all pools return to zero and stay there across a full-year warp.

  • H-3HighRemediated

    Re-pricing the yield vesting period could claw back vested yield and open a dilution mint

    Reproduced three times. Fixed by crystallizing before re-pricing, then tightened again when the first entry guard was shown to still leave most of the stream skimmable. Confirmed dead in the 22 July re-audit.

  • H-4HighRemediated

    The mint gate proved attestations existed but not that they attested to the facility's terms

    Receivable classes had no on-chain binding between the attested bundle and the facility's economic terms. A terms hash is now bound and re-checked on the funding path as well as at origination.

  • H-5HighRemediated

    Nothing on-chain forced a receivable to be marked down between a missed payment and a servicer default

    Redesigned rather than patched, across two rounds. Past-due marking is now a permissionless but reversible accounting flag that cannot set the defaulted state, cannot freeze the curator, and cannot de-gate the loss cascade: the attested default declaration remains the only path to those. A residual in which a cured facility kept a stale mark was closed by a repayment hook wired into both performing branches of the waterfall.

  • H-6HighDeferred

    Absorbed junior capital has no on-chain claim on later recoveries

    Accepted in principle and deferred on-chain by owner decision: handled off-chain while Forest Road is the curator, with the on-chain recovery leg a required build before a junior tranche or a third-party curator. The architecture document was corrected because it had promised an on-chain leg the code does not implement.

  • PM-H-01HighRemediated

    Revoking a valuation permitted rollback to an older signed mark

    A monotonic high-watermark now survives revocation. The direct reset lever was subsequently removed entirely by owner decision, leaving recovery to a timelocked upgrade.

  • PM-H-02HighRemediated

    The points loss-freeze was bypassable by a permissionless checkpoint

    Closed in source with regression coverage.

  • PM-H-03HighRemediated

    The conservative redemption NAV was specified but not implemented

    Implemented across the engine, the resolve hook, the vault and the queue, with fifteen tests and two new stateful invariants.

  • PM-H-04HighRemediated

    The production deployment path was not mainnet ready

    Resolved by the dedicated mainnet deployment, configuration and validation scripts. Preparing that path is not authorization to use it.

  • PM-H-05HighRemediated

    The frontend was hardwired to testnet and mock-stable assumptions

    The build is now chain-pinned at build time and a production build fails closed unless it can verify its deployment receipt.

  • PM-H-06HighRemediated

    A global recovery assessment survived a changed impairment book

    Assessments are now bound to an impairment revision that invalidates them when the book moves. Deployed and exercised on Sepolia.

  • PM-R-11HighRemediated

    The conservative NAV under-marked impairment after partial backstop coverage

    Externally reported and reproduced with a 150,000-unit under-mark measured, because the NAV subtracted global backstop capacity while coverage is capped and consumed per event. Coverage consumption is now recorded per default and released per facility, deliberately aggregated so the result may over-mark but never under-mark.

  • PM-M-01MediumAccepted

    Concentration exposure could drift above the configured limit after a decrease

    Reclassified as a disclosed admission-control posture: drift is published on-chain and a breached dimension cannot be grown further. Remains an economic and governance item for sign-off.

  • PM-M-02MediumSuperseded

    Frontend approval handling assumed standard-return stablecoins

    Scoped out rather than fixed: mainnet v1 is canonical USDC only. Any second stablecoin requires new testing and a new audit.

  • PM-M-03MediumRemediated

    The documentation route rendered repository markdown as raw HTML

    The renderer now discards raw HTML and applies a safe URL transform, with regression tests. This is the route these audit pages are served from.

  • PM-M-04MediumRemediated

    The production frontend had no content-security or framing protection

    Content security policy, frame-ancestors, strict transport, nosniff, referrer and permissions policies are now set and asserted by the frontend test suite.

  • PM-M-05MediumRemediated

    The queue interface hid older claimable positions

    Resolved by direct request-identifier lookup and claim, so a position outside the scan window is still reachable.

  • PM-R-02MediumRemediated

    The reserve pause did not cover the debt-service reserve primitives

    Pause scope widened to the outflow primitives it had omitted.

  • PM-R-09MediumRemediated

    Mint-gate attestation masks were not validated as exact known-bit masks

    Governance can no longer set a mask bit outside the known set, so a future attestation kind cannot be accepted by governance while remaining unread by the gate.

  • R4-AC1MediumAccepted

    The realized-loss magnitude is chosen by the servicer rather than bound to an attestation

    Confirmed real and pre-existing; accepted and folded into the documented attestation and servicer trust model. Constraining it is a counsel decision, not a code decision.

  • PM-R-01MediumOpen

    The Sepolia deployment is deliberately testnet-shaped and must not be copied to production

    Open by design, and the reason a testnet result is not a production result: the testnet stack retains bootstrap administrative privileges, uses a mock stablecoin, and runs with concentration limits open for ramp testing. The production validator refuses each of those postures.

  • PM-R-04MediumRemediated

    No fresh coverage measurement existed for the current tree

    Declared a test-rigor blocker at the time. A source-only coverage gate now reports every source-defined contract function and line entered.

  • PM-R-05LowRemediated

    The redemption-queue request layout was fresh-deploy-only

    Resolved by the clean-v1 fresh-deployment-only path.

  • PM-R-07LowRemediated

    The backstop per-event coverage cap was enforced per call

    Coverage is now snapshotted and tracked per event rather than per call.

  • PM-R-08LowRemediated

    Streaming rewards with no stakers stranded them

    Notifying rewards with a zero staked supply now reverts rather than silently stranding the stream. This closes one leg of the Round 1 reward-dust finding.

  • PM-R-10MediumRemediated

    The deployed testnet queue was stale relative to the redesigned cooldown

    Resolved by redeploying. The validator correctly failed loudly on the stale manifest rather than passing it.

What this round was

This was the largest and most adversarial campaign run against the protocol, and the one that found the most serious defects. It ran in four connected stages over six days:

  1. A manual pre-mainnet review of contracts, frontend, deployment configuration, invariants and fork validation, producing the readiness register.
  2. An adversarial red-team fleet: per-contract, specialist and protocol-wide reviewers attacking independently on isolated local forks. Every submitted finding was put to a panel of independent refuters before it was accepted; of fifty-six submissions, thirty-six were refuted and roughly nine distinct findings survived deduplication. The severities published here are the panel-adjudicated values, not the values as filed.
  3. A twenty-four-lens full-codebase register in which each lens attacked independently and was forbidden to run the test suite, followed by a reproduction phase that turned forty-three findings into executable proofs. Every entry was labelled as reproduced or reasoning-only.
  4. Two go/no-go re-audits of the resulting fix diff, each run with the explicit posture that another incomplete fix should be assumed until disproven, and each requiring the original defect to be re-run and shown dead rather than argued dead.

What it found

The headline result was a Critical: under a fully-marked unrealized impairment, queue settlement could burn an entire queued position and pay out exactly zero. It was reproduced seven times.

Its history is the most instructive thing in this whole audit record. The same mechanism had already been filed a week earlier, in Round 2, as an Informational item, a queued request could become sub-wei dust and burn for nothing, and closed on the reasoning that an amount below one wei was immaterial. Its recommendation was never implemented. When the conservative redemption NAV was introduced days later, that change destroyed the premise: the clamp could price a whole position at zero, not at a sub-wei residual, and the burn proceeded anyway.

An Informational finding was accepted on an argument about magnitude rather than a bound in the code, and a later change falsified the argument while the code stayed as it was. That is the failure mode this campaign exists to catch, and it is why findings on this site record the premise of an acceptance rather than only its outcome.

Five further High findings concerned backing inflation through treasury-directed funding, a permanently stranded impairment pool after partial recovery, a dilution mint opened by re-pricing the yield vesting period, a mint gate that proved attestations existed without proving they attested to the facility's terms, and the absence of any on-chain force to mark a receivable down between a missed payment and a servicer default. All five are recorded closed, each by re-running the original reproduction rather than by inspection.

The campaign also recorded that a first round of parallel fixes was rejected in its entirety, every one reviewed as incomplete, nothing applied, with upgrade-safety blindness and knowingly-red test suites named as the two systemic causes.

What it did not close

Two findings were deferred rather than fixed, and both remain live commitments:

  • Absorbed junior capital has no on-chain claim on later recoveries. Accepted in principle, handled off-chain while Forest Road is itself the curator, and identified as a required build before a junior tranche or any third-party curator exists. The architecture document was corrected because it had described an on-chain leg the code does not implement.
  • The realized-loss magnitude is chosen by the servicer rather than bound to an attestation. Confirmed real, pre-existing, and folded into the documented attestation and servicer trust model. Constraining it is a counsel decision rather than a code decision.

One further item is open by design and is the single most important caveat on any testnet result reported anywhere on this site: the testnet deployment is deliberately testnet-shaped. It retains bootstrap administrative privileges, uses a mock stablecoin with no value, and runs with concentration limits open for ramp testing. The production validator refuses every one of those postures. A green result on that stack is evidence about the code, not evidence about a production configuration.

Method note on the numbers

Severities here are adjudicated, and several moved during adjudication, two findings filed High were reduced to Medium, one filed High was reduced to Low, and one was raised. Findings that were reproduced with an executable proof are distinguished throughout the internal reports from those established by reasoning alone; roughly a third of the full-codebase register was reasoning-only and is marked as such there.

Fourteen further reported claims were refuted outright and recorded as refuted, so that a later round would not re-derive them and count them again.

Why these reports are not published in full

The underlying reports for this campaign are held internally rather than published, and the reason is specific rather than reflexive. Several of them contain step-by-step, measured exploitation recipes for defects whose fix status is stated in a different document; the operational posture of the live testnet stack in enough detail to target it; and local filesystem and endpoint detail from the reviewers' own environments. Publishing an exploitation recipe alongside an incomplete statement of what is fixed would be worse than publishing nothing.

What is published is the finding, its adjudicated severity, and its current disposition, which is the part a reader needs in order to judge the protocol.

Limitations

The full-codebase register explicitly recorded what it did not cover: nothing was executed by the lenses themselves, coverage was not measured in that round: the handover script was unread, and economic calibration, most of the frontend, individual test files, manifest drift, observability, servicer-outage liveness, and gas, static-analysis and storage-layout diffs were all out of scope. Two of its findings concerned false greens in the test and invariant layers, both reproduced by mutation, a reminder that a passing suite is evidence only to the extent its assertions bind.

An independent external audit remains a required production gate.

Earlier roundFive-pass source review, Round 2→