CVE-2024-49753
Executive Summary
CVE-2024-49753 is a server-side request forgery (SSRF) vulnerability in Zitadel, an open-source identity infrastructure platform. The flaw resides in the URL validation mechanism of Zitadel actions, specifically the isHostBlocked check, which is intended to block requests to localhost (127.0.0.1). An attacker can bypass this restriction by creating a DNS record that resolves to 127.0.0.1, allowing actions to send requests to internal endpoints. This could lead to unauthorized access to sensitive internal services or data. The vulnerability has a CVSS score of 5.9 (Medium) and affects multiple versions prior to the patched releases. No public proof-of-concept (PoC) or exploit code is currently available.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Zitadel is distributed as a Go binary and Docker image. The vulnerability is in the core application logic, not in a package dependency. However, organizations using Zitadel should verify the integrity of their deployment artifacts and ensure they are sourced from official channels. The patch is included in the latest releases, and no known workarounds exist.
CVSS Breakdown & Threat Level
- CVSS Score: 5.9 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L
- Attack Vector: Network (AV:N) – The vulnerability is exploitable remotely.
- Attack Complexity: Low (AC:L) – No special conditions are required.
- Privileges Required: Low (PR:L) – An attacker needs a valid account with permissions to create actions.
- User Interaction: None (UI:N) – No user action is needed.
- Scope: Unchanged (S:U) – The vulnerable component and the impacted component are the same.
- Confidentiality Impact: Low (C:L) – Limited access to internal data.
- Integrity Impact: Low (I:L) – Potential to modify internal state.
- Availability Impact: Low (A:L) – Could cause minor service disruption.
Threat Level: Medium. The vulnerability requires authenticated access and is limited to SSRF, but it could be chained with other weaknesses to escalate impact.
Deep Dive & Mechanics
The vulnerability is a classic SSRF bypass via DNS rebinding or controlled DNS resolution. Zitadel actions allow users to define custom logic that can make HTTP requests. The isHostBlocked function is designed to prevent requests to localhost (127.0.0.1) by checking the resolved IP address. However, the check is performed at the time of action creation or validation, not at the time of request execution. An attacker can:
- Create a DNS record (e.g.,
attacker-controlled-domain.com) that initially resolves to a legitimate external IP. - After the
isHostBlockedcheck passes, change the DNS record to resolve to127.0.0.1. - When the action executes, the request is sent to
127.0.0.1, bypassing the security control.
This allows the attacker to probe internal services (e.g., databases, admin panels, or cloud metadata endpoints) that are bound to localhost.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-Patch):
The isHostBlocked function likely performs a single DNS lookup at validation time and caches the result. Example pseudocode:
func isHostBlocked(host string) bool {
ips, _ := net.LookupHost(host)
for _, ip := range ips {
if ip == "127.0.0.1" {
return true
}
}
return false
}
This is vulnerable because the DNS resolution is not re-evaluated at request time.
Patched Code (Post-Patch): The fix likely involves performing the DNS lookup at request execution time or using a more robust validation that prevents DNS rebinding. Example:
func isHostBlocked(host string) bool {
// Use a short TTL or force re-resolution
ips, _ := net.DefaultResolver.LookupHost(context.Background(), host)
for _, ip := range ips {
if ip == "127.0.0.1" {
return true
}
}
return false
}
Additionally, the patched version may block requests to private IP ranges entirely, not just 127.0.0.1.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A Zitadel instance running a vulnerable version (e.g., 2.64.0).
- A valid user account with permissions to create or modify actions.
- A domain name with DNS control (e.g., via a free DNS service).
Exploitation Steps:
- Set up DNS: Create a DNS A record for
evil.example.compointing to a public IP (e.g.,1.2.3.4). - Create a Zitadel action: Define an action that makes an HTTP request to
http://evil.example.com/internal-endpoint. - Trigger the action: Execute the action (e.g., via a login flow). The
isHostBlockedcheck passes becauseevil.example.comresolves to1.2.3.4. - Change DNS: Update the DNS record for
evil.example.comto point to127.0.0.1. - Re-trigger the action: The action now sends a request to
http://127.0.0.1/internal-endpoint, potentially accessing internal services.
Example Action Code:
// Zitadel action (JavaScript)
function execute(ctx) {
let response = http.get("http://evil.example.com/admin");
// Process response
}
Expected Outcome: The attacker can access internal endpoints, such as cloud metadata (e.g., http://169.254.169.254/) or local services.
Blue Team
Detection:
- Monitor DNS query logs for unusual patterns, such as domains that change resolution frequently or resolve to private IPs.
- Alert on actions that make HTTP requests to domains with short TTLs or that have been recently created.
- Use network monitoring to detect outbound requests to private IP ranges from Zitadel servers.
Hunting:
- Search for Zitadel actions that use
http.getorhttp.postwith external URLs. - Review DNS logs for queries to domains that later resolve to
127.0.0.1or other private IPs.
Mitigation:
- Apply the patch immediately.
- Restrict action creation to trusted users only.
- Implement network segmentation to limit the impact of SSRF.
Indicators of Compromise (IOCs)
- Network: Outbound HTTP requests from Zitadel to private IP ranges (e.g.,
127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16). - DNS: Queries for domains with rapidly changing A records or short TTLs.
- Logs: Zitadel audit logs showing actions with URLs that resolve to localhost.
- File: Modified or newly created Zitadel action definitions with suspicious URLs.
Detection Engineering
YARA Rule
rule CVE_2024_49753_Zitadel_SSRF {
meta:
description = "Detects Zitadel action definitions with potential SSRF indicators"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2024-49753"
strings:
$http_get = "http.get" nocase
$http_post = "http.post" nocase
$url_pattern = /https?:\/\/[a-zA-Z0-9.-]+\/[a-zA-Z0-9\/_-]+/
condition:
$http_get or $http_post and #url_pattern > 0
}
Sigma Rule
title: Zitadel SSRF via DNS Bypass
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects outbound HTTP requests from Zitadel to private IP ranges
author: Valters IT
date: 2025-04-10
logsource:
category: network
product: zeek
detection:
selection:
dest_ip:
- "127.0.0.0/8"
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
source_port: 8080 # Zitadel default HTTP port
condition: selection
falsepositives:
- Legitimate internal monitoring
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2024-49753 Zitadel SSRF Attempt"; flow:to_server; content:"Host|3a|"; pcre:"/Host\x3a\s*(127\.0\.0\.1|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})/i"; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate Patch: Upgrade Zitadel to version 2.64.1, 2.63.6, 2.62.8, 2.61.4, 2.60.4, 2.59.5, or 2.58.7 (depending on your release line).
- Network Controls: Implement egress filtering to block outbound traffic to private IP ranges from Zitadel servers.
- Access Control: Restrict the ability to create or modify actions to trusted administrators only.
- Monitoring: Enable logging for all action executions and monitor for suspicious HTTP requests.
- DNS Security: Use DNS filtering to block domains with short TTLs or known malicious patterns.
- No Workarounds: The vendor states no workarounds are available; patching is mandatory.
Valters IT
DevSecOps & Cyber Threat Intelligence