T09 · Insecure Skill Coding Practices
- Location
scripts/dex_quote.py:247- Finding
Floating-Point Conversion Can Alter Financial Quote Amounts
- Content
View full analysis
Vulnerability Details
File Location:
scripts/dex_quote.py, lines 247–260 and line 383
Vulnerability Type: Numeric precision loss in financial amount processing
Risk Level: MediumVulnerable Code
python @staticmethod def to_raw_amount(human_amount: float, decimals: int) -> str: """Convert human-readable amount to raw amount string. Uses integer math to avoid floating-point precision issues. """ # Handle decimal amounts by splitting on '.' amount_str = f"{human_amount:.{decimals}f}" if "." in amount_str: integer_part, decimal_part = amount_str.split(".") decimal_part = decimal_part[:decimals].ljust(decimals, "0") raw = int(integer_part) * (10 ** decimals) + int(decimal_part) else: raw = int(amount_str) * (10 ** decimals) return str(raw)The command-line interface introduces the same issue:
python parser.add_argument("--amount", type=float, required=True, help="Human-readable amount")Technical Analysis
Token amounts require exact fixed-point arithmetic. The CLI parses the user-supplied decimal as an IEEE-754 binary floating-point value, and
to_raw_amount()also declares and processes the value as afloat. Many decimal values cannot be represented exactly in binary floating point. Large values and values near token-unit boundaries can therefore be rounded before conversion into raw units.Formatting the already-rounded float does not recover the original user input. This implementation also contradicts the guidance in
SKILL.md, which explicitly states that Python amount calculations should never usefloat().The resulting raw amount is included in the authenticated request. Consequently, the API may quote an amount different from the one entered by the user.
Attack Path
- A user or calling application supplies a precision-sensitive decimal through
--amount. argparseconver ...[truncated 1048 chars]
- A user or calling application supplies a precision-sensitive decimal through
- Remediation
View remediation
Remediation Suggestions
-
Accept human-readable amounts as strings rather than floats.
-
Parse them using
decimal.Decimalwith explicit validation. -
Reject negative, zero, non-finite, exponential, and over-precision values as appropriate.
-
Convert to raw units using exact decimal or integer arithmetic.
-
Change the CLI argument to preserve the original input:
python parser.add_argument( "--amount", type=str, required=True, help="Human-readable decimal amount", ) -
Use an exact conversion implementation, for example:
python from decimal import Decimal, InvalidOperation @staticmethod def to_raw_amount(human_amount: str, decimals: int) -> str: if not isinstance(decimals, int) or decimals < 0: raise ValueError("decimals must be a non-negative integer") try: value = Decimal(human_amount) except InvalidOperation as exc: raise ValueError("Invalid decimal amount") from exc if not value.is_finite() or value <= 0: raise ValueError("Amount must be finite and greater than zero") scale = Decimal(10) ** decimals scaled = value * scale if scaled != scaled.to_integral_value(): raise ValueError( f"Amount has more than {decimals} decimal places" ) return str(int(scaled)) -
Add tests for values such as
0.1, the smallest supported token unit, values with excessive precision, and large quantities.
-
