T09 · Insecure Skill Coding Practices
Error
- Location
- src/signing.ts:280
- Finding
- Server-Controlled EIP-7702 Authorization Is Signed Without Chain or Implementation Allowlisting<![CDATA[ ## Vulnerability Details **File Location**: `src/signing.ts:280-298`; `scripts/prepare-sign-execute.ts:366-392`; `scripts/prepare-sign-execute.ts:706-742` **Vulnerability Type**: Untrusted EIP-7702 authorization signing **Risk Level**: High ### Vulnerable Code From `src/signing.ts:280-298`: ```ts if (envelope.eip7702AuthRequest) { const authRequest = envelope.eip7702AuthRequest as { contractAddress?: string; chainId?: number; nonce?: number | string; }; if (!authRequest.contractAddress || typeof authRequest.chainId !== 'number') { throw new Error('intentEnvelope.eip7702AuthRequest is invalid.'); } const txCount = await publicClient.getTransactionCount({ address: signer.address }); const nonce = typeof authRequest.nonce === 'number' ? authRequest.nonce : typeof authRequest.nonce === 'string' ? Number(authRequest.nonce) : Number(txCount); const auth = await signer.signAuthorization({ contractAddress: authRequest.contractAddress as Address, chainId: authRequest.chainId, nonce, }); ``` From `scripts/prepare-sign-execute.ts:366-392`: ```ts let authorization: SetupPayload['authorization'] = null; if (setupType === 'full') { const authRaw = setup.authorization; if (!isRecord(authRaw)) { throw new Error('setup.authorization is missing (required for full setup).'); } const contractAddress = authRaw.contractAddress; if (typeof contractAddress !== 'string' || !ADDRESS_RE.test(contractAddress)) { throw new Error('setup.authorization.contractAddress is missing or invalid.'); } const chainId = authRaw.chainId; if (typeof chainId !== 'number' || !Number.isInteger(chainId) || chainId <= 0) { throw new Error('setup.authorization.chainId is missing or invalid.'); } authorization = { contractAddress: contractAddress as Address, chainId }; } ``` From `scripts/prepare-sign-execute.ts:706-742`: ```ts if (!setupPayload.authorization) { throw new Error('Full setup requi ...[truncated 3718 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Maintain a local allowlist of audited EIP-7702 implementation addresses for each supported chain. 2. Require `authRequest.chainId`, `setup.authorization.chainId`, `envelope.chainId`, and `preflight.chain.chainId` to be identical. 3. Reject authorization requests containing server-selected nonces unless they exactly match a nonce obtained from a trusted, explicitly configured RPC. 4. Do not rely on documentation or relay behavior to enforce fork-only execution. Use a staging-specific chain domain or another cryptographic mechanism that prevents production-chain replay. 5. Decode and validate all associated setup calldata before authorization. 6. Present the delegation target, chain, nonce, and decoded action to the user and require explicit approval before live signing. 7. Authenticate prepare responses or verify them against a locally defined signing policy before invoking either the local signer or Privy. ]]>
