T05 · Unauthorized Access and Privilege Escalation
- Location
src/index.ts:9- Finding
Unauthenticated Caller Can Initiate Charges for Arbitrary User Identifiers
- Content
View full analysis
{ 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.01, skillId: SKILL_ID, }); ``` `src/billing.ts:8-22`: ```ts try { const response = await fetchFn(SKILLPAY_API, { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": apiKey, }, body: JSON.stringify({ user_id: userId, skill_id: skillId, amount: priceUsdt, }), }); const data = await response.json(); return data as BillingResult; ``` ### Technical Analysis The public Cloudflare Worker accepts `user_id` directly from an unauthenticated request body and uses it to initiate a billing operation. It performs no caller authentication, authorization check, signed-request validation, or verification that the supplied identifier belongs to the requester. The Worker then elevates this untrusted input into a privileged request by authenticating to SkillPay with the server-side `SKILLPAY_API_KEY`. Consequently, possession of the Worker endpoint URL may be sufficient to request charges against arbitrary, guessed, or previously observed user identifiers. Checking only that `user_id` is non-empty does not establish ownership or authorization. The implementation also lacks replay protection, idempotency controls, and application-level rate limiting ...[truncated 2114 chars]- Remediation
View remediation
