T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/spandex_trade.mjs:499
- Finding
- Remote EIP-712 Order Data Is Signed Without Local Intent Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/spandex_trade.mjs:499-522` and `scripts/spandex_trade.mjs:559-578` **Vulnerability Type**: Insufficient validation of remotely supplied signing payloads **Risk Level**: High ### Vulnerable Code ```js const signMsgRes = await fetch(`${KYBER_LO_DOMAIN}/write/api/v1/orders/sign-message`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(unsignedBody), }).then(r => r.json()); if (signMsgRes.code !== 0) die(`KyberSwap sign-message failed: ${signMsgRes.message}`); const eip712Data = signMsgRes.data; // Sign + submit const signature = await walletClient.signTypedData({ domain: { ...eip712Data.domain, chainId: parseInt(eip712Data.domain.chainId) }, types: { Order: eip712Data.types.Order }, primaryType: 'Order', message: eip712Data.message, }); const createRes = await fetch(`${KYBER_LO_DOMAIN}/write/api/v1/orders`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...unsignedBody, salt: eip712Data.message.salt, signature }), }).then(r => r.json()); ``` The same pattern is used when canceling an order: ```js const cancelSignRes = await fetch(`${KYBER_LO_DOMAIN}/write/api/v1/orders/cancel-sign`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chainId: '8453', maker: account.address, orderIds: [parseInt(args['order-id'])] }), }).then(r => r.json()); if (cancelSignRes.code !== 0) die(`KyberSwap cancel-sign failed: ${cancelSignRes.message}`); const eip712Data = cancelSignRes.data; const signature = await walletClient.signTypedData({ domain: { ...eip712Data.domain, chainId: parseInt(eip712Data.domain.chainId) }, types: { CancelOrder: eip712Data.types.CancelOrder }, primaryType: 'CancelOrder', message: eip712Data.message, }); const cancelRes = await fetch(`${KYBER_LO_DOMAIN}/write/api/v1/orders/cancel`, { method: 'POST', headers: { 'Content-Type': 'applicatio ...[truncated 1938 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Construct the complete EIP-712 message locally wherever the protocol permits. - Before signing, require the returned chain ID to equal Base chain ID `8453`. - Allowlist the expected verifying contract for the selected operation. - Compare the maker, assets, amounts, expiration, and order IDs byte-for-byte against locally derived values. - Validate the exact EIP-712 domain name, version, primary type, and field schema. - Reject extra fields, unsupported schemas, unexpected contracts, invalid addresses, and mismatched values. - Display the validated signing terms and require explicit confirmation before producing an asset-affecting signature. - Add tests using malicious API responses with modified contracts, assets, amounts, makers, and order IDs. ]]>
