---
id: "CVE-2026-54442"
kind: "vulnerability"
aliases: ["CVE-2026-54442", "GHSA-c6q7-wqw2-h65w"]
title: "NationalSecurityAgency/emissary has an incomplete fix for CVE-2026-35571"
severity: "medium"
cvss: 4.8
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "gov.nsa.emissary:emissary", "fixed": ["8.51.0"], "affected": "< 8.51.0", "ecosystem": "maven"}]
ecosystems: ["maven"]
tags: ["cwe-918", "emissary", "java", "maven", "package", "self-hosted"]
not_affected_if: ["no-navigation-links", "version-8.51.0-or-later"]
published_at: "2026-10-30T22:51:19+00:00"
first_seen_at: "2026-10-30T22:51:45+00:00"
updated_at: "2026-10-30T22:52:36+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-c6q7-wqw2-h65w", "first_seen_at": "2026-10-30T22:51:45+00:00"}]
---

# NationalSecurityAgency/emissary has an incomplete fix for CVE-2026-35571

The URL validation regex added to emissary's NavAction.java accepts protocol-relative and single-slash URLs, so the fix for CVE-2026-35571 is incomplete. An attacker can send users to attacker-controlled hosts or make the server request internal services, including cloud metadata endpoints.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- maven:gov.nsa.emissary:emissary affected < 8.51.0 fixed 8.51.0

## How to check

- Check the `gov.nsa.emissary:emissary` version in your build file; versions below `8.51.0` are affected.
- Look for the `VALID_LINK` pattern `^(https?:/)?/.*` in `NavAction.java` (around line 47).

## Fix

- `gov.nsa.emissary:emissary` `8.51.0` is the fixed version per the product range, but the advisory says the fix is incomplete, so confirm the regex in that release.

## Timeline

- 2026-10-30T22:51:45+00:00 ghsa https://github.com/advisories/GHSA-c6q7-wqw2-h65w

## Documents

- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/NationalSecurityAgency/emissary/security-advisories/GHSA-c6q7-wqw2-h65w
- [advisory] Maintainer's advisory: github.com https://github.com/NationalSecurityAgency/emissary/security/advisories/GHSA-c6q7-wqw2-h65w
- [advisory] Maintainer's advisory: github.com https://github.com/NationalSecurityAgency/emissary/security/advisories/GHSA-cpm7-cfpx-3hvp
- [fix] Patch: github.com https://github.com/NationalSecurityAgency/emissary/commit/e2078417464b9004620dde28dcbca2f73ea06c13
- [fix] Release: github.com https://github.com/NationalSecurityAgency/emissary/releases/tag/8.39.0

## From the sources

### 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

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
