ghsa-c6q7-wqw2-h65w
CVSS 4.8 osv_maven### 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: ```java 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 ```python """ 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:** 1. Run `python3 poc.py` 2. 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
- Published
- unknown
- Last Modified
- unknown
CVSS details not available.
No product information available.
- 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/e0179f7558cfb09a5bbc63a2f9fcb50f899768f6
- https://github.com/NationalSecurityAgency/emissary/commit/e2078417464b9004620dde28dcbca2f73ea06c13
- https://github.com/NationalSecurityAgency/emissary
- https://github.com/NationalSecurityAgency/emissary/releases/tag/8.39.0
- https://github.com/NationalSecurityAgency/emissary/releases/tag/8.51.0
No linked vulnerabilities found.
{
"affected": [
{
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-c6q7-wqw2-h65w/GHSA-c6q7-wqw2-h65w.json"
},
"package": {
"ecosystem": "Maven",
"name": "gov.nsa.emissary:emissary",
"purl": "pkg:maven/gov.nsa.emissary/emissary"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "8.51.0"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"8.0.0",
"8.1.0",
"8.10.0",
"8.11.0",
"8.11.1",
"8.12.0",
"8.13.0",
"8.14.0",
"8.15.0",
"8.16.0",
"8.17.0",
"8.18.0",
"8.19.0",
"8.19.1",
"8.2.0",
"8.20.0",
"8.21.0",
"8.22.0",
"8.23.0",
"8.24.0",
"8.25.0",
"8.26.0",
"8.27.0",
"8.28.0",
"8.29.0",
"8.3.0",
"8.30.0",
"8.31.0",
"8.32.0",
"8.33.0",
"8.34.0",
"8.35.0",
"8.36.0",
"8.37.0",
"8.38.0",
"8.39.0",
"8.4.0",
"8.40.0",
"8.41.0",
"8.42.0",
"8.43.0",
"8.44.0",
"8.45.0",
"8.46.0",
"8.47.0",
"8.48.0",
"8.49.0",
"8.5.0",
"8.50.0",
"8.6.0",
"8.7.0",
"8.7.1",
"8.8.0",
"8.9.0"
]
}
],
"aliases": [
"CVE-2026-54442"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-30T22:51:19Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\n\nThe 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.\n\n### Affected Package\n\n- **Ecosystem:** Maven\n- **Package:** NationalSecurityAgency/emissary\n- **Affected versions:** < e2078417464b\n- **Patched versions:** >= e2078417464b\n\n### Severity\n\nMedium\n\n### CWE\n\nCWE-918 — Server-Side Request Forgery (SSRF)\n\n### Details\n\nThe fix in `NavAction.java` (line 47) introduces a `VALID_LINK` pattern:\n\n```java\nPattern.compile(\"^(https?:/)?/.*\")\n```\n\nThis regex is intended to restrict navigation links to relative paths and HTTP/HTTPS URLs. However, it has multiple bypass vectors.\n\nProtocol-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.\n\nSingle-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.\n\nProtocol-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.\n\nThe 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.\n\n### PoC\n\n```python\n\"\"\"\nCVE-2026-35571 - NationalSecurityAgency/emissary SSRF via NavAction\n\nThe fix in commit e2078417464b adds URL scheme validation using:\n Pattern.compile(\"^(https?:/)?/.*\")\n\nThis allows protocol-relative URLs (//evil.com) and single-slash variants\n(http:/evil.com) to bypass the validation.\n\nTested against: emissary@0d4dc56 (pre-fix) and patch e207841\nExtracted from: src/main/java/emissary/server/mvc/NavAction.java:47\n\"\"\"\n\nimport re\nimport sys\n\nFIXED_PATTERN = re.compile(r\"^(https?:/)?/.*\")\n\n\ndef vulnerable_accepts(link: str) -> bool:\n \"\"\"Pre-fix behaviour: no validation, everything passes.\"\"\"\n return True\n\n\ndef fixed_accepts(link: str) -> bool:\n \"\"\"Post-fix behaviour: must match VALID_LINK pattern.\"\"\"\n return bool(FIXED_PATTERN.match(link))\n\n\nTEST_VECTORS = [\n (\"javascript: XSS payload\",\n \"javascript:alert(document.cookie)\", True),\n (\"ftp: scheme\",\n \"ftp://evil.com/exfil\", True),\n (\"data: URI\",\n \"data:text/html,<script>alert(1)</script>\", True),\n\n (\"Relative path\",\n \"/path/to/resource\", False),\n (\"HTTP URL\",\n \"http://trusted.internal:8080/api\", False),\n (\"HTTPS URL\",\n \"https://trusted.internal/api\", False),\n\n (\"Protocol-relative URL to attacker host (//evil.com)\",\n \"//evil.com/steal?c=SESSION\", True),\n (\"Protocol-relative with embedded credentials\",\n \"//user:pass@evil.com/path\", True),\n (\"Protocol-relative to cloud metadata (//169.254.169.254)\",\n \"//169.254.169.254/latest/meta-data/\", True),\n (\"Backslash trick (\\\\\\\\evil.com)\",\n \"\\\\\\\\evil.com/path\", True),\n (\"Tab in scheme (java\\\\tscript:...)\",\n \"java\\tscript:alert(1)\", True),\n (\"Path starting with attacker-like host (/evil.com)\",\n \"/evil.com\", False),\n (\"Triple slash (///evil.com)\",\n \"///evil.com/etc/passwd\", True),\n (\"http:/ single-slash to attacker host\",\n \"http:/evil.com/steal\", True),\n (\"https:/ single-slash to attacker host\",\n \"https:/evil.com/steal\", True),\n (\"URL-encoded javascript scheme (%6a...)\",\n \"%6aavascript:alert(1)\", True),\n (\"CRLF injection in path\",\n \"/legit\\r\\nLocation: http://evil.com\", True),\n]\n\n\ndef main():\n print(\"=\" * 72)\n print(\"CVE-2026-35571 -- Emissary NavAction SSRF / Open-Redirect PoC\")\n print(\"Pattern under test: ^(https?:/)?/.*\")\n print(\"=\" * 72)\n print()\n\n bypasses_found = []\n results_table = []\n\n for desc, url, should_block in TEST_VECTORS:\n vuln_result = vulnerable_accepts(url)\n fixed_result = fixed_accepts(url)\n\n if should_block and fixed_result:\n status = \"BYPASS\"\n bypasses_found.append((desc, url))\n elif should_block and not fixed_result:\n status = \"BLOCKED (good)\"\n elif not should_block and fixed_result:\n status = \"ALLOWED (good)\"\n elif not should_block and not fixed_result:\n status = \"FALSE-POS\"\n else:\n status = \"UNKNOWN\"\n\n results_table.append((desc, url, vuln_result, fixed_result, status))\n\n for desc, url, vuln, fixed, status in results_table:\n display_url = repr(url) if len(url) > 50 else url\n print(f\"[{status:>15}] {desc}\")\n print(f\"{'':>17} URL: {display_url}\")\n print(f\"{'':>17} pre-fix={vuln} post-fix={fixed}\")\n print()\n\n print(\"=\" * 72)\n print(f\"Total vectors tested : {len(TEST_VECTORS)}\")\n print(f\"Bypasses found : {len(bypasses_found)}\")\n print()\n\n if bypasses_found:\n print(\"VULNERABILITY CONFIRMED -- the following vectors bypass the fix:\")\n print()\n for desc, url in bypasses_found:\n print(f\" - {desc}\")\n print(f\" URL: {repr(url)}\")\n print()\n print(\"Key finding: The regex ^(https?:/)?/.* allows protocol-relative\")\n print(\"URLs (//evil.com/...) because the optional group (https?:/) can be\")\n print(\"absent, leaving //.* which matches //attacker.com. This enables\")\n print(\"SSRF to arbitrary external hosts via navigation links.\")\n print()\n print(\"Additionally, http:/evil.com and https:/evil.com match the regex\")\n print(\"(group 1 captures 'http:/' or 'https:/') and browsers normalise\")\n print(\"these to http://evil.com, enabling open redirect / SSRF.\")\n sys.exit(0)\n else:\n print(\"No bypasses found -- fix appears complete.\")\n sys.exit(1)\n\n\nif __name__ == \"__main__\":\n main()\n\n```\n\n**Steps to reproduce:**\n1. Run `python3 poc.py`\n2. Observe that protocol-relative and single-slash URLs bypass the regex\n\n**Expected output:**\n```\nVULNERABILITY CONFIRMED\nProtocol-relative URLs (//evil.com/) and single-slash variants (http:/evil.com) bypass the regex validation.\n```\n\n### Impact\n\nAn 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.\n\n### Suggested Remediation\n\nReplace 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.\n\n### References\n\n- Incomplete fix commit: https://github.com/NationalSecurityAgency/emissary/commit/e2078417464b9004620dde28dcbca2f73ea06c13\n- Original CVE: CVE-2026-35571",
"id": "GHSA-c6q7-wqw2-h65w",
"modified": "2026-11-04T22:30:04.054271913Z",
"published": "2026-10-30T22:51:19Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/NationalSecurityAgency/emissary/security/advisories/GHSA-c6q7-wqw2-h65w"
},
{
"type": "WEB",
"url": "https://github.com/NationalSecurityAgency/emissary/security/advisories/GHSA-cpm7-cfpx-3hvp"
},
{
"type": "WEB",
"url": "https://github.com/NationalSecurityAgency/emissary/commit/e0179f7558cfb09a5bbc63a2f9fcb50f899768f6"
},
{
"type": "WEB",
"url": "https://github.com/NationalSecurityAgency/emissary/commit/e2078417464b9004620dde28dcbca2f73ea06c13"
},
{
"type": "PACKAGE",
"url": "https://github.com/NationalSecurityAgency/emissary"
},
{
"type": "WEB",
"url": "https://github.com/NationalSecurityAgency/emissary/releases/tag/8.39.0"
},
{
"type": "WEB",
"url": "https://github.com/NationalSecurityAgency/emissary/releases/tag/8.51.0"
}
],
"schema_version": "1.9.2",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "NationalSecurityAgency/emissary has an incomplete fix for CVE-2026-35571"
}