T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:185
- Finding
- Unauthenticated Telegram Webhook Allows Fraudulent Credit Grants<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 185-210 **Vulnerability Type**: Unauthenticated webhook and untrusted payment data **Risk Level**: High ### Vulnerable Code ```python @app.post("/webhook/telegram") async def telegram_webhook(request: Request): data = await request.json() # Must answer pre_checkout_query within 10 seconds pq = data.get("pre_checkout_query") if pq: httpx.post( f"https://api.telegram.org/bot{BOT_TOKEN}/answerPreCheckoutQuery", json={"pre_checkout_query_id": pq["id"], "ok": True}, timeout=8, ) return {"ok": True} msg = data.get("message", {}) payment = msg.get("successful_payment") if payment: # payload format: "credits_20_697391377" parts = payment.get("invoice_payload", "").split("_") if len(parts) == 3 and parts[0] == "credits": credits = int(parts[1]) user_id = parts[2] total = add_credits(user_id, credits) notify_user(user_id, credits, total) return {"ok": True} ``` ### Technical Analysis The public Telegram webhook does not authenticate incoming requests. It does not verify Telegram's webhook secret header or otherwise establish that a request originated from Telegram. The handler treats the request body's `successful_payment` object as authoritative and directly derives both the number of credits and the target user from the attacker-controlled `invoice_payload`. It does not validate: - The webhook source - The Telegram payer identity - The expected invoice payload - The package identifier - The amount paid - The `XTR` currency - A Telegram payment charge identifier - Whether the transaction was previously processed Consequently, possession of a valid bot payment event is unnecessary. Any client that can reach the endpoint can construct a synthetic payment update. The absence of transaction-level idempotency also permits the same su ...[truncated 1323 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Set a cryptographically random `secret_token` when registering the Telegram webhook. 2. Verify the `X-Telegram-Bot-Api-Secret-Token` header using constant-time comparison before parsing or processing a request. 3. Reject any request with a missing or invalid secret. 4. Define payment packages exclusively on the server. The invoice payload should contain an opaque package or order identifier rather than an authoritative credit amount. 5. Validate the payer's Telegram ID, invoice payload, currency, and total amount against the server-side order record. 6. Use `telegram_payment_charge_id` as an idempotency key and store it in a transactional database with a unique constraint. 7. Apply the credit update and transaction-record insertion in one atomic database transaction. 8. Reject unknown packages, nonpositive credit values, mismatched users, unexpected currencies, and previously processed transactions. 9. Restrict the endpoint behind TLS, ingress filtering, rate limits, and request-size limits. ]]>
