T09 · Insecure Skill Coding Practices
- Location
SKILL.md:429- Finding
Unbounded Automatic Cryptocurrency Payment from Untrusted XMR402 Challenges
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 429–447
Vulnerability Type: Automatic payment authorization using attacker-controlled challenge fields
Risk Level: HighVulnerable Code
python def call_with_xmr402(url: str, method: str = "GET", headers: dict = {}, **kwargs) -> httpx.Response: """Hit a URL; if it returns 402 with XMR402 challenge, pay via Ripley Pocket and retry.""" resp = httpx.request(method, url, headers=headers, **kwargs) if resp.status_code != 402: return resp www_auth = resp.headers.get("WWW-Authenticate", "") if not www_auth.startswith("XMR402"): return resp # Not an XMR402 challenge # Parse the challenge challenge = parse_xmr402_challenge(www_auth) address = challenge["address"] amount = int(challenge["amount"]) / 1e12 # piconeros → XMR message = challenge["message"] # Pay via Ripley Pocket (synchronous — returns txid + proof) pay_resp = httpx.post(f"{RIPLEY_URL}/xmr402/pay", headers=PAY_HEADERS, json={ "address": address, "amount": amount, "message": message, }).json()Technical Analysis
The helper treats the
address,amount, andmessagevalues in an HTTPWWW-Authenticateresponse as authorization to initiate an irreversible cryptocurrency payment. These fields are controlled by the remote endpoint that returns the response.After checking only that the header begins with
XMR402, the function submits the supplied destination and amount to the authenticated/xmr402/payendpoint. It does not require user confirmation or enforce a maximum payment amount, cumulative spending budget, trusted-origin policy, destination allowlist, or balance-based safety threshold. It also does not validate the challenge timestamp or expiration.Consequently, any malicious or compromised endpoint contacted through this helper can request a payment to an attacker-selected Monero address. Redirects may create an ...[truncated 1703 chars]
- Remediation
View remediation
Remediation Suggestions
- Require explicit user approval before submitting every payment. Present the normalized destination address, XMR amount, network fee, merchant origin, and total debit.
- Enforce a strict configurable maximum amount per transaction and cumulative spending limits per session, merchant, and time period.
- Permit automatic payment only for explicitly allowlisted HTTPS origins and expected destination addresses. Revalidate the final origin after every redirect or disable redirects for payment-triggering requests.
- Validate every challenge field before payment:
- Require all mandatory fields.
- Reject non-numeric, negative, zero, non-finite, or excessive amounts.
- Validate the complete Monero address format.
- Check timestamp freshness and expiration.
- Reject duplicate or replayed messages.
- Check the account balance and calculated fee before requesting payment. Refuse transactions that would exceed a configured reserve threshold.
- Bind approval to the exact request method, URL, body digest, merchant origin, amount, address, and nonce so that approval cannot be reused for a different request.
- Record an auditable authorization decision for each payment and provide a mechanism to disable automatic XMR402 handling.
- Replace the mutable default argument with a safe default:
python def call_with_xmr402( url: str, method: str = "GET", headers: dict | None = None, **kwargs, ) -> httpx.Response: headers = {} if headers is None else dict(headers)
