Skip to content

[Audit] [MEDIUM] deploy-all verifier does not prove primary native terminal wiring for CPN REV or BAN #99

Description

@mejango

Audit seed

Deep Nemesis / deploy-all-v6 / all script/**/*.sol and src/**/*.sol / deployment verifier and wiring

Repos involved

  • deploy-all-v6

Root cause

script/Verify.s.sol checks exact native-primary-terminal equality only for project 1 (NANA). For projects 2-4 (CPN, REV, BAN), it only checks that:

  • directory.primaryTerminalOf(projectId, NATIVE_TOKEN) is nonzero, and
  • JBMultiTerminal appears somewhere in the project's terminal list.

Clean deployment configures JBMultiTerminal as terminalConfigs[0] for every canonical project, so the verifier should assert the same exact primary terminal for every canonical project.

Impact

A drifted deployment can leave CPN, REV, or BAN with a wrong native-token primary terminal while still passing verification. Any user flow, frontend, or integration that relies on directory.primaryTerminalOf(projectId, NATIVE_TOKEN) can route value through the wrong terminal despite the deployment being certified.

This is a deployment wiring failure: correct runtime contracts can still be assembled into an unsafe or unintended topology.

Proof of concept

  1. Clean deployment intends JBMultiTerminal as the first/native terminal for all canonical projects.
  2. A deployment drift or admin action changes project 2, 3, or 4's native primary terminal to some other nonzero terminal while keeping JBMultiTerminal in the terminal list.
  3. _verifyDirectoryWiring() passes because the primary is nonzero and the terminal list contains JBMultiTerminal.
  4. _verifyRoutes() checks primaryTerminalOf(..., NATIVE_TOKEN) == terminal only for project 1.
  5. The verifier can report all checks passed for wrong primary terminal wiring on projects 2-4.

Relevant code:

  • script/Deploy.s.sol:2077-2088: REV terminal config puts _terminal first
  • script/Deploy.s.sol:2180-2191: CPN terminal config puts _terminal first
  • script/Deploy.s.sol:2353-2364: NANA terminal config puts _terminal first
  • script/Deploy.s.sol:2480-2491: BAN terminal config puts _terminal first
  • script/Verify.s.sol:376-383: only checks primary terminal is nonzero for every project
  • script/Verify.s.sol:385-402: only checks JBMultiTerminal is somewhere in the terminal list
  • script/Verify.s.sol:888-893: exact primary equality check only covers NANA/project 1

Why this survived self-review

The strongest counterargument is that terminal-list membership may be sufficient. It is not: the directory stores a distinct primary terminal for a token, and integrations commonly use the primary terminal lookup to decide where to send native-token flows. Membership does not prove routing intent.

Recommended fix

Assert exact native-primary-terminal equality for every canonical project:

for (uint256 i; i < projectIds.length; i++) {
    _check(
        address(directory.primaryTerminalOf(projectIds[i], JBConstants.NATIVE_TOKEN)) == address(terminal),
        string.concat(labels[i], " primary native terminal is JBMultiTerminal"),
        true
    );
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions