T09 · Insecure Skill Coding Practices
- Location
index.js:6- Finding
Unsafe Floating-Point Conversion of Token Transfer Amount
- Content
View full analysis
Vulnerability Details
File Location:
index.js:6-14
Vulnerability Type:T09: Insecure Skill Coding Practices
Risk Level: Mediumjs const { amount: amt, toAddress, chain = 'Solana', privateKey } = input; if (!amt || !toAddress || !privateKey) { return { status: 'failed', message: 'Missing required parameters: amount, toAddress, privateKey' }; } try { const wh = await Wormhole('Testnet', [chain]); const transferAmount = BigInt(amt * 1_000_000); // USDC has 6 decimalsTechnical Analysis
The transfer amount is multiplied using JavaScript's IEEE-754
Numberarithmetic before it is converted toBigInt. Decimal token amounts cannot always be represented exactly as binary floating-point values. As a result:amt * 1_000_000may produce a non-integer, causingBigInt()to throw.- Large values may exceed
Number.MAX_SAFE_INTEGERand lose precision before conversion. - The validation only checks whether
amtis truthy. It does not ensure that the value is finite, positive, within an acceptable transfer limit, or expressed with no more than six decimal places. - Negative values and some numeric strings can pass the initial validation.
- No explicit upper bound protects against accidental or maliciously induced oversized transfers.
Because this value controls a financial transaction, floating-point conversion and incomplete range validation can affect transaction integrity.
Attack Path
- A caller supplies a negative, excessively large, malformed, or precision-sensitive
amount. - The truthiness check accepts the value.
- JavaScript coerces and multiplies the value using floating-point arithmetic.
- The result either loses precision, becomes unsuitable for
BigInt(), or represents an amount outside the intended policy. - The Skill fails or passes the resulting integer to the Wormhole transfer operation.
- If the SDK and underlying chain accept the result, t ...[truncated 518 chars]
- Remediation
View remediation
Remediation Suggestions
- Require
amountto be a decimal string rather than a JavaScript number. - Validate it against a strict positive-decimal format with no more than six fractional digits.
- Reject signs, exponents,
NaN, infinity, empty values, and unsupported types. - Define an explicit maximum transfer amount and require additional confirmation for high-value transfers.
- Convert the validated decimal string without floating-point arithmetic. Split it into integer and fractional components, right-pad the fraction to six digits, and combine the components using
BigInt. - Validate that the final base-unit amount is greater than zero and within protocol limits before constructing the transaction.
- Add tests for fractional values, values near precision boundaries, negative inputs, excess decimal places, and oversized inputs.
- Require
