Skip to content

Mock wallet connector ships a hardcoded private key: NEXT_PUBLIC_MOCK_WALLET=true signs real-looking transactions #820

Description

@nanaf6203-bit

Mock wallet connector ships a hardcoded private key: NEXT_PUBLIC_MOCK_WALLET=true signs real-looking transactions

Labels / Complexity: bug · security · Medium Complexity — Medium

Problem

src/config/mockConnector.ts creates a wagmi connector from a hardcoded private key committed to the repository:

const account = privateKeyToAccount(
  "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
);

and src/config/wagmi.ts (line 120) swaps it into the connector list whenever NEXT_PUBLIC_MOCK_WALLET === "true":

const connectors =
  process.env.NEXT_PUBLIC_MOCK_WALLET === "true"
    ? [mockConnector]
    : [injected()];

The connector also reports isAuthorized() { return true; } unconditionally. Consequences:

  • Any build with the flag set signs with a publicly-known key. If NEXT_PUBLIC_MOCK_WALLET=true is ever set in a staging or production-like environment — or copied from a demo config — every transaction the UI "confirms" is signed with 0x4f3e…b1d, which anyone can now sign as. The key's address is public and the key is burned.
  • The mock is indistinguishable from a real connection. useAuth/useWalletConnector flows treat the mock account as a connected wallet, so demo-mode code paths look production-correct while being unsafe.

Root cause

src/config/mockConnector.ts (hardcoded privateKeyToAccount(...) key) and src/config/wagmi.ts line 120 (env-flag activation without a NODE_ENV guard).

Why this is architecturally hard

  1. Mocking must be scoped, not flagged. The correct design keeps the mock out of production builds entirely (e.g. NODE_ENV !== "production" AND the flag, or a separate entry point). A contributor must decide the guard and prove the mock cannot activate in a production build (next build output check or a test that asserts the connector list in production mode).
  2. The committed key must be treated as compromised. The key's address should never be funded on any real network, and the mock should generate a random key per session (or use viem's generatePrivateKey) instead of a fixed one, so no long-lived secret exists to leak.

Acceptance criteria

  • The mock connector cannot activate when NODE_ENV === "production" (or equivalent build-time guard), and a test asserts the production connector list contains no mock.
  • The hardcoded private key is removed; the mock (if kept for local dev) uses a generated per-session key.
  • Documentation (env example/README) states that NEXT_PUBLIC_MOCK_WALLET is dev-only.
  • npm run typecheck, npm test, and npm run lint pass.

Out of scope

Redesigning the wallet-connection UI is out of scope; this issue is the mock's key and activation scope.

Getting started

  • src/config/mockConnector.ts — the hardcoded key and isAuthorized override
  • src/config/wagmi.ts — the connector selection at line 120

Commands: npm run typecheck, npm test, npm run lint, npm run build.

Good first files to read: src/config/mockConnector.ts, src/config/wagmi.ts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Medium ComplexitybugSomething isn't working correctlysecuritySecurity issue or hardening opportunity

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions