T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/place-bet.js:188
- Finding
- Remote Bet Payload Is Signed and Submitted Without Complete Destination and Domain Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/place-bet.js:188-291` **Vulnerability Type**: Insufficient validation of a remotely supplied EIP-712 payload and submission URL **Risk Level**: High ### Vulnerable Code ```js const payload = JSON.parse(Buffer.from(betRes.encoded, 'base64').toString('utf8')) const cd = payload.signableClientBetData const payloadStake = BigInt(cd.bet?.amount ?? cd.bets?.[0]?.amount ?? cd.amount ?? 0) const payloadCondId = cd.bet?.conditionId ?? cd.bets?.[0]?.conditionId const payloadOutcome = cd.bet?.outcomeId ?? cd.bets?.[0]?.outcomeId const coreAddr = cd.clientData?.core?.toLowerCase() if (String(payloadStake) !== String(stakeAmount)) { console.error(`❌ Payload stake mismatch: expected ${stakeAmount}, got ${payloadStake}`) process.exit(1) } if (String(payloadCondId) !== String(conditionId)) { console.error(`❌ conditionId mismatch: expected ${conditionId}, got ${payloadCondId}`) process.exit(1) } if (String(payloadOutcome) !== String(outcomeId)) { console.error(`❌ outcomeId mismatch: expected ${outcomeId}, got ${payloadOutcome}`) process.exit(1) } if (coreAddr.toLowerCase() !== CLIENT_CORE.toLowerCase()) { console.error(`❌ Core address mismatch: expected ${CLIENT_CORE}, got ${coreAddr}`) process.exit(1) } const primaryType = payload.types.ClientComboBetData ? 'ClientComboBetData' : 'ClientBetData' const bettorSignature = await walletClient.signTypedData({ account, domain: payload.domain, types: payload.types, primaryType, message: payload.signableClientBetData, }) const submitUrl = new URL(payload.apiUrl) const submitHost = submitUrl.hostname const submitPath = submitUrl.pathname + submitUrl.search const submitRes = await postJson(submitHost, submitPath, { environment: payload.environment, bettor, betOwner: bettor, clientBetData: payload.apiClientBetData, bettorSignature, }) ``` ### Technical Analysis The Pinwin API supplies the EIP-712 domain, type definitions, signed ...[truncated 1647 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Allowlist the exact HTTPS submission host and permitted order paths. - Reject URLs containing unexpected ports, credentials, fragments, or redirects. - Require Polygon chain ID `137` in the EIP-712 domain. - Pin the expected domain name, version, and verifying contract. - Define the EIP-712 schema locally instead of trusting `payload.types`. - Validate every signed field, including relayer, expiration, fee, environment, affiliate, sponsorship, owner, and nonce. - Enforce an explicit maximum relayer fee approved by the user. - Display all validated fields before confirmation. - Fail closed if any expected field is absent or has an unexpected type. ]]>
