You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
POST /api/alerts is a fully unauthenticated endpoint that operates as a public Telegram message delivery service and SSRF relay. Three distinct attack vectors exist: (1) action: "test" sends arbitrary HTML messages to any Telegram user ID, (2) action: "create" with channel: "webhook" registers an alert that will POST to any attacker-controlled URL from the server, and (3) action: "list" enumerates all registered alert configs including destination chat IDs. The GET /api/alerts response self-documents all attack paths.
Evidence
File: src/app/api/alerts/route.ts
// Zero authentication — no bearer token, no API key, no session checkexportasyncfunctionPOST(request: Request){const{ action, ...data}=awaitrequest.json();switch(action){case'test': {// Sends arbitrary Telegram message to any chat IDsent=awaitsendTelegram(data.destination,message);// data.destination = attacker-controlled}case'create': {// Registers webhook alert — server will POST to any URLconstalert: AlertConfig={channel: data.channel||'telegram',destination: data.destination,// any URL or chat ID
...
};}case'list': {// Returns ALL registered alerts including destination chat IDsreturnNextResponse.json({alerts: userAlerts});}}}
The GET /api/alerts response includes a usage field that documents the attack surface in plain text:
SSRF: Setting channel: "webhook" and destination: "http://169.254.169.254/latest/meta-data/" causes the server to reach cloud metadata endpoints, internal services, or exfiltrate data.
Alert enumeration: action: "list" returns all registered alert configs — no userId scoping prevents cross-user enumeration.
Attack or failure scenario
# Instant Telegram phishing to any user
curl -X POST https://feed.xdc.network/api/alerts \
-H 'Content-Type: application/json' \
-d '{"action":"test","channel":"telegram","destination":"353201749"}'# SSRF to AWS metadata endpoint
curl -X POST https://feed.xdc.network/api/alerts \
-d '{"action":"create","type":"severity","value":"CRITICAL","channel":"webhook","destination":"http://169.254.169.254/latest/meta-data/iam/security-credentials/"}'
Root cause
Zero authentication was implemented. The endpoint was designed as a client-configurable alert system but deployed as a public HTTP route with no access controls and no input sanitization on the destination field.
Recommended fix
Require auth on all /api/alerts requests (bearer token at minimum).
Validate destination on webhook channel: allowlist known safe URLs or block private IP ranges (RFC 1918, link-local 169.254.0.0/16, loopback).
Never return other users' alert destinations in list responses.
Remove the self-documenting usage field from the GET response.
Acceptance criteria
All /api/alerts actions require authenticated requests; 401 returned without valid token.
Webhook destination validated against a blocklist of private/internal IP ranges.
action: "list" scoped to authenticated user only.
GET /api/alerts does not expose usage documentation with example payloads.
Suggested labels
security, bug
Priority
P0
Severity
Critical — unauthenticated Telegram delivery to arbitrary users and SSRF via webhook channel.
Confidence
Confirmed — no authentication exists and the SSRF vector is present in current HEAD.
Summary
POST /api/alertsis a fully unauthenticated endpoint that operates as a public Telegram message delivery service and SSRF relay. Three distinct attack vectors exist: (1)action: "test"sends arbitrary HTML messages to any Telegram user ID, (2)action: "create"withchannel: "webhook"registers an alert that will POST to any attacker-controlled URL from the server, and (3)action: "list"enumerates all registered alert configs including destination chat IDs. TheGET /api/alertsresponse self-documents all attack paths.Evidence
File:
src/app/api/alerts/route.tsThe
GET /api/alertsresponse includes ausagefield that documents the attack surface in plain text:{ "usage": { "testAlert": "POST /api/alerts { action: \"test\", channel: \"telegram\", destination: \"123456789\" }" } }Why this matters
SUBSCRIBERSlist in issue PII violation: real names and Telegram user IDs of 4 private individuals committed in plain text to public repo #58) can deliver arbitrary HTML-formatted messages through the legitimate GlobeNewsLive bot.channel: "webhook"anddestination: "http://169.254.169.254/latest/meta-data/"causes the server to reach cloud metadata endpoints, internal services, or exfiltrate data.action: "list"returns all registered alert configs — no userId scoping prevents cross-user enumeration.Attack or failure scenario
Root cause
Zero authentication was implemented. The endpoint was designed as a client-configurable alert system but deployed as a public HTTP route with no access controls and no input sanitization on the
destinationfield.Recommended fix
/api/alertsrequests (bearer token at minimum).destinationonwebhookchannel: allowlist known safe URLs or block private IP ranges (RFC 1918, link-local 169.254.0.0/16, loopback).listresponses.usagefield from the GET response.Acceptance criteria
/api/alertsactions require authenticated requests; 401 returned without valid token.destinationvalidated against a blocklist of private/internal IP ranges.action: "list"scoped to authenticated user only.GET /api/alertsdoes not expose usage documentation with example payloads.Suggested labels
security, bug
Priority
P0
Severity
Critical — unauthenticated Telegram delivery to arbitrary users and SSRF via webhook channel.
Confidence
Confirmed — no authentication exists and the SSRF vector is present in current HEAD.