GHSA-c6q7-wqw2-h65w

Suggest an improvement
Source
https://github.com/advisories/GHSA-c6q7-wqw2-h65w
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-c6q7-wqw2-h65w/GHSA-c6q7-wqw2-h65w.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-c6q7-wqw2-h65w
Aliases
  • CVE-2026-54442
Published
2026-10-30T22:51:19Z
Modified
2026-10-30T23:00:04Z
Severity
  • 4.8 (Medium) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N CVSS Calculator
Summary
NationalSecurityAgency/emissary has an incomplete fix for CVE-2026-35571
Details

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:

  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

Database specific
{
    "cwe_ids":  [
        "CWE-918"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-10-30T22:51:19Z",
    "nvd_published_at":  null,
    "severity":  "MODERATE"
}
References

Affected packages

Maven / gov.nsa.emissary:emissary

Package

Name
gov.nsa.emissary:emissary
View open source insights on deps.dev
Purl
pkg:maven/gov.nsa.emissary/emissary

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
8.51.0

Affected versions

8.*
8.0.0
8.1.0
8.2.0
8.3.0
8.4.0
8.5.0
8.6.0
8.7.0
8.7.1
8.8.0
8.9.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.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.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.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.50.0

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"