T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- src/index.ts:20
- Finding
- Caller-Controlled Billing Identity Allows Potential Unauthorized Charges<![CDATA[ ## Vulnerability Details **File Location**: `src/index.ts:20-34` **Vulnerability Type**: Missing authorization for a sensitive billing operation **Risk Level**: High ### Vulnerable Code ```ts const body = await request.json() as { user_id: string; country?: "MY" | "SG"; }; 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.02, skillName: "my-sg-invoice-parser", }); ``` ### Technical Analysis The public request handler obtains `user_id` directly from untrusted request JSON and uses it to perform a billing operation authenticated with the server-side `SKILLPAY_API_KEY`. The visible code does not authenticate the caller, verify ownership of the supplied billing identity, require a signed authorization token, or derive the user identity from a trusted session. The TypeScript type assertion on `request.json()` provides no runtime validation or authorization. Consequently, possession or discovery of another user's identifier may be sufficient to request a charge against that identity. Billing is part of the functionality declared in `SKILL.md`, so contacting the billing service and using the API key are necessary in principle. However, allowing callers to select the account to be charged exceeds least privilege unless the unavailable `../../shared/billing` implementation independently and reliably validates user authorization. The imported billing helper is outside the supplied project. Its endpoint, authorization controls, and handling of `SKILLPAY_API_KEY` could not be reviewed. The vulnerability is therefore directly confirmed at the endpoint authorization boundary, while successful financial exploitation depends on whether the external helper performs an additional authorization check. ### Attack Path 1. An attacker obtains or guesses another customer's `user_id`. 2. The attacker submits a ...[truncated 1341 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Authenticate every billing request** - Require a verified session, signed access token, or equivalent authentication mechanism before initiating a charge. - Reject anonymous requests to the billing endpoint. 2. **Do not trust a billing identity supplied in request JSON** - Derive the chargeable `userId` from authenticated server-side identity claims. - If a request includes `user_id`, compare it with the authenticated identity and reject mismatches. 3. **Require transaction-specific authorization** - Use short-lived, signed billing intents that bind the user, Skill name, price, expiration time, and unique nonce. - Verify the signature and all bound values before calling `chargeUser`. 4. **Add replay and duplicate-charge protection** - Require an idempotency key for each logical parsing transaction. - Persist completed transaction identifiers for an appropriate retention period and reject replays. - Ensure the downstream billing service also enforces idempotency. 5. **Apply abuse controls** - Rate-limit requests per authenticated user, account, and source. - Detect abnormal charge frequency and temporarily block suspicious activity. - Record security audit events without logging API keys or unnecessary personal data. 6. **Perform runtime input validation** - Validate the JSON body with a strict schema. - Enforce expected identifier format and length, reject unknown properties where practical, and handle malformed JSON safely. 7. **Harden the billing helper** - Confirm that `../../shared/billing` sends data only to the intended HTTPS billing endpoint. - Ensure it independently verifies authorization rather than treating possession of a user ID as authority to charge. - Limit the API key to this Skill, the fixed price, and only the billing operations required. - Rotate the key if exposure is suspected and prevent it from appearing in responses or logs. 8. **Add secur ...[truncated 254 chars]
