T09 · Insecure Skill Coding Practices
- Location
src/index.ts:9- Finding
Unauthenticated and Replayable Billing Requests
- Content
View full analysis
Vulnerability Details
File Location:
src/index.ts, lines 9-24
Vulnerability Type: Missing authentication, authorization, and replay protection on a billing operation
Risk Level: HighVulnerable Code
ts if (request.method !== "POST") { return Response.json({ error: "POST required" }, { status: 405 }); } const body = await request.json() as { user_id: string }; if (!body.user_id) { return Response.json({ error: "user_id required" }, { status: 400 }); } const billing = await chargeUser({ userId: body.user_id, apiKey: env.SKILLPAY_API_KEY, priceUsdt: 0.03, skillName: "sea-whatsapp-business-bot", }); if (!billing.success) {Technical Analysis
The public request handler accepts an arbitrary caller-provided
user_idand immediately passes it to the privileged billing function. The only validation is that the identifier is non-empty.The handler does not authenticate the caller, verify that the caller owns or is authorized to bill the supplied identifier, require a signed request, enforce an idempotency key, or implement visible replay and rate-limiting controls. Consequently, possession or discovery of another user's identifier may be sufficient to request charges against that user.
The unavailable
../../shared/billingimplementation might contain additional safeguards, but no such protection is established by the supplied project. Security controls inside that dependency therefore cannot be relied upon or verified in this audit.Attack Path
- An attacker discovers or guesses a valid user identifier.
- The attacker sends a request to the public
/respondendpoint:http POST /respond Content-Type: application/json {"user_id":"victim-user-id"} - The handler accepts the identifier without authenticating the requester or checking ownership.
- The Worker invokes
chargeUserusing its server-sideSKILLPAY_API_KEY.
...[truncated 751 chars]
- Remediation
View remediation
Remediation Suggestions
- Authenticate every caller before permitting a billing operation.
- Derive the billing identity from the authenticated principal instead of trusting a caller-supplied
user_id. - If an identifier must be submitted, cryptographically bind it to the authenticated session and verify authorization server-side.
- Require signed requests with a short expiration time and a unique nonce.
- Require an idempotency key for each legitimate invocation and persist its result so retries cannot cause duplicate charges.
- Apply per-account and per-source rate limits, spending limits, and anomaly detection.
- Return an appropriate authorization error when identity verification fails.
- Verify that
chargeUserindependently validates authorization and prevents duplicate charges. - Add tests covering forged identifiers, repeated requests, expired signatures, duplicate idempotency keys, and concurrent replay attempts.
