CVE-2026-54442
Mở trang đầy đủCVSS 4.8 MEDIUM Lộ dữ liệu
NationalSecurityAgency/emissary has an incomplete fix for CVE-2026-35571
Mô tả
Summary
The URL validation regex ^(https?:/)?/.* added to emissary's NavAction.java allows protocol-relative URLs (//evil.com/...) and single-slash scheme variants (http:/evil.com) to bypass validation, enabling SSRF and open redirect attacks.
Affected Package
- Ecosystem: Maven
- Package: NationalSecurityAgency/emissary
- Affected versions: < e2078417464b
- Patched versions: >= e2078417464b
Severity
Medium
CWE
CWE-918 — Server-Side Request Forgery (SSRF)
Details
The fix in NavAction.java (line 47) introduces a VALID_LINK pattern:
Pattern.compile("^(https?:/)?/.*")
This regex is intended to restrict navigation links to relative paths and HTTP/HTTPS URLs. However, it has multiple bypass vectors.
Protocol-relative URLs (//evil.com/...): The group (https?:/)? is optional, so the pattern reduces to //.* when the group is absent. This matches //evil.com/steal?c=SESSION, which browsers resolve to the current page's protocol plus the attacker's host.
Single-slash scheme (http:/evil.com): The regex group captures http:/ as a valid match, and browsers normalize http:/evil.com to http://evil.com, creating an open redirect to the attacker's server.
Protocol-relative to cloud metadata (//169.254.169.254/...): This enables SSRF to cloud instance metadata endpoints, which is particularly dangerous in AWS/GCP environments where IAM credentials can be retrieved.
The pre-fix code had no validation at all, accepting any URL. The fix blocks javascript:, ftp:, and data: URIs, but the protocol-relative and single-slash bypasses remain exploitable.
PoC
"""
CVE-2026-35571 - NationalSecurityAgency/emissary SSRF via NavAction
The fix in commit e2078417464b adds URL scheme validation using:
Pattern.compile("^(https?:/)?/.*")
This allows protocol-relative URLs (//evil.com) and single-slash variants
(http:/evil.com) to bypass the validation.
Tested against: emissary@0d4dc56 (pre-fix) and patch e207841
Extracted from: src/main/java/emissary/server/mvc/NavAction.java:47
"""
import re
import sys
FIXED_PATTERN = re.compile(r"^(https?:/)?/.*")
def vulnerable_accepts(link: str) -> bool:
"""Pre-fix behaviour: no validation, everything passes."""
return True
def fixed_accepts(link: str) -> bool:
"""Post-fix behaviour: must match VALID_LINK pattern."""
return bool(FIXED_PATTERN.match(link))
TEST_VECTORS = [
("javascript: XSS payload",
"javascript:alert(document.cookie)", True),
("ftp: scheme",
"ftp://evil.com/exfil", True),
("data: URI",
"data:text/html,<script>alert(1)</script>", True),
("Relative path",
"/path/to/resource", False),
("HTTP URL",
"http://trusted.internal:8080/api", False),
("HTTPS URL",
"https://trusted.internal/api", False),
("Protocol-relative URL to attacker host (//evil.com)",
"//evil.com/steal?c=SESSION", True),
("Protocol-relative with embedded credentials",
"//user:pass@evil.com/path", True),
("Protocol-relative to cloud metadata (//169.254.169.254)",
"//169.254.169.254/latest/meta-data/", True),
("Backslash trick (\\\\evil.com)",
"\\\\evil.com/path", True),
("Tab in scheme (java\\tscript:...)",
"java\tscript:alert(1)", True),
("Path starting with attacker-like host (/evil.com)",
"/evil.com", False),
("Triple slash (///evil.com)",
"///evil.com/etc/passwd", True),
("http:/ single-slash to attacker host",
"http:/evil.com/steal", True),
("https:/ single-slash to attacker host",
"https:/evil.com/steal", True),
("URL-encoded javascript scheme (%6a...)",
"%6aavascript:alert(1)", True),
("CRLF injection in path",
"/legit\r\nLocation: http://evil.com", True),
]
def main():
print("=" * 72)
print("CVE-2026-35571 -- Emissary NavAction SSRF / Open-Redirect PoC")
print("Pattern under test: ^(https?:/)?/.*")
print("=" * 72)
print()
bypasses_found = []
results_table = []
for desc, url, should_block in TEST_VECTORS:
vuln_result = vulnerable_accepts(url)
fixed_result = fixed_accepts(url)
if should_block and fixed_result:
status = "BYPASS"
bypasses_found.append((desc, url))
elif should_block and not fixed_result:
status = "BLOCKED (good)"
elif not should_block and fixed_result:
status = "ALLOWED (good)"
elif not should_block and not fixed_result:
status = "FALSE-POS"
else:
status = "UNKNOWN"
results_table.append((desc, url, vuln_result, fixed_result, status))
for desc, url, vuln, fixed, status in results_table:
display_url = repr(url) if len(url) > 50 else url
print(f"[{status:>15}] {desc}")
print(f"{'':>17} URL: {display_url}")
print(f"{'':>17} pre-fix={vuln} post-fix={fixed}")
print()
print("=" * 72)
print(f"Total vectors tested : {len(TEST_VECTORS)}")
print(f"Bypasses found : {len(bypasses_found)}")
print()
if bypasses_found:
print("VULNERABILITY CONFIRMED -- the following vectors bypass the fix:")
print()
for desc, url in bypasses_found:
print(f" - {desc}")
print(f" URL: {repr(url)}")
print()
print("Key finding: The regex ^(https?:/)?/.* allows protocol-relative")
print("URLs (//evil.com/...) because the optional group (https?:/) can be")
print("absent, leaving //.* which matches //attacker.com. This enables")
print("SSRF to arbitrary external hosts via navigation links.")
print()
print("Additionally, http:/evil.com and https:/evil.com match the regex")
print("(group 1 captures 'http:/' or 'https:/') and browsers normalise")
print("these to http://evil.com, enabling open redirect / SSRF.")
sys.exit(0)
else:
print("No bypasses found -- fix appears complete.")
sys.exit(1)
if __name__ == "__main__":
main()
Steps to reproduce:
- Run
python3 poc.py - Observe that protocol-relative and single-slash URLs bypass the regex
Expected output:
VULNERABILITY CONFIRMED
Protocol-relative URLs (//evil.com/) and single-slash variants (http:/evil.com) bypass the regex validation.
Impact
An attacker can craft navigation links that bypass URL validation to redirect users to attacker-controlled servers (open redirect) or make the emissary server issue requests to internal services (SSRF). The //169.254.169.254/latest/meta-data/ bypass is particularly dangerous in cloud environments, enabling retrieval of IAM credentials.
Suggested Remediation
Replace the regex with one that explicitly rejects protocol-relative URLs. Alternatively, parse the URL with java.net.URI and validate the scheme and host against an allowlist rather than relying on regex.
References
- Incomplete fix commit: https://github.com/NationalSecurityAgency/emissary/commit/e2078417464b9004620dde28dcbca2f73ea06c13
- Original CVE: CVE-2026-35571
Điểm và phân loại
- CVSS
- 4.8 MEDIUM v3.1
- Nguồn điểm
- GitHub Advisory
- Mức độ (theo nguồn)
- MEDIUM
- EPSS
- —
- CWE
- CWE-918
Vector CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N
Ảnh hưởng
| Package | Bản bị ảnh hưởng | Bản đã sửa |
|---|---|---|
maven gov.nsa.emissary:emissary |
< 8.51.0 |
8.51.0
|
Vì sao bị lọc
- CVSS 4.8 < 8.0 và không thuộc CISA KEV
Loại tác động
- Lộ dữ liệu
- CWE-918; từ khoá "ssrf"; từ khoá "server-side request forgery"
Dữ liệu riêng của nguồn
- OSV.dev · ID
- GHSA-c6q7-wqw2-h65w
Tham khảo
- https://github.com/advisories/GHSA-c6q7-wqw2-h65w
- https://github.com/NationalSecurityAgency/emissary/security/advisories/GHSA-c6q7-wqw2-h65w
- https://github.com/NationalSecurityAgency/emissary/security/advisories/GHSA-cpm7-cfpx-3hvp
- https://github.com/NationalSecurityAgency/emissary/commit/e2078417464b9004620dde28dcbca2f73ea06c13
- https://github.com/NationalSecurityAgency/emissary/releases/tag/8.39.0
- https://osv.dev/vulnerability/GHSA-c6q7-wqw2-h65w
- https://github.com/NationalSecurityAgency/emissary