Medium severity4.8NVD Advisory· Published Apr 7, 2026· Updated Apr 27, 2026
CVE-2026-35571
CVE-2026-35571
Description
Emissary is a P2P based data-driven workflow engine. Prior to 8.39.0, Mustache navigation templates interpolated configuration-controlled link values directly into href attributes without URL scheme validation. An administrator who could modify the navItems configuration could inject javascript: URIs, enabling stored cross-site scripting (XSS) against other authenticated users viewing the Emissary web interface. This vulnerability is fixed in 8.39.0.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
gov.nsa.emissary:emissaryMaven | < 8.39.0 | 8.39.0 |
Affected products
1Patches
1e2078417464bui :: validate nav links (#1293)
3 files changed · +63 −3
src/main/java/emissary/server/mvc/NavAction.java+19 −1 modified@@ -8,16 +8,21 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import org.glassfish.jersey.server.mvc.Template; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; import java.util.stream.Collectors; @Path("") // context is emissary public class NavAction { + private static final Logger logger = LoggerFactory.getLogger(NavAction.class); + EmissaryNav nav; public NavAction() throws IOException { @@ -39,6 +44,8 @@ public EmissaryNav nav() { public static class EmissaryNav { + private static final Pattern VALID_LINK = Pattern.compile("^(https?:/)?/.*"); + String appName; String appVersion; List<NavItem> navItems; @@ -77,7 +84,18 @@ public void setNavButtons(Map<String, String> navButtons) { } protected static List<NavItem> convert(Map<String, String> map) { - return map.entrySet().stream().map(e -> new NavItem(e.getKey(), e.getValue())).collect(Collectors.toList()); + return map.entrySet().stream() + .filter(e -> isValidLink(e.getValue())) + .map(e -> new NavItem(e.getKey(), e.getValue())) + .collect(Collectors.toList()); + } + + private static boolean isValidLink(String link) { + if (!VALID_LINK.matcher(link).matches()) { + logger.warn("Skipping invalid navigation link '{}'", link); + return false; + } + return true; } public static class NavItem {
src/main/resources/templates/nav.mustache+2 −2 modified@@ -8,12 +8,12 @@ <ul class="navbar-nav me-auto"> {{#navItems}} <li class="nav-item"> - <a class="nav-link" href="{{link}}">{{display}}</a> + <a class="nav-link" href="{{link}}" rel="noopener noreferrer">{{display}}</a> </li> {{/navItems}} {{#navButtons}} <li class="nav-item"> - <a href="{{link}}" class="btn btn-danger navbar-btn" style="margin: 2px 2px 0px 0px;" onclick="return confirm('Are you sure?')">{{display}}</a> + <a href="{{link}}" rel="noopener noreferrer" class="btn btn-danger navbar-btn" style="margin: 2px 2px 0px 0px;" onclick="return confirm('Are you sure?')">{{display}}</a> </li> {{/navButtons}} </ul>
src/test/java/emissary/server/mvc/NavActionTest.java+42 −0 added@@ -0,0 +1,42 @@ +package emissary.server.mvc; + +import emissary.server.mvc.NavAction.EmissaryNav; + +import org.apache.commons.collections4.CollectionUtils; +import org.junit.jupiter.api.Test; + +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class NavActionTest { + + @Test + void navItems() { + + var navItems = new LinkedHashMap<String, String>(); + navItems.put("Item1", "/path/to/resource"); + navItems.put("Item2", "http://testing1.com"); + navItems.put("Item3", "https://testing2.com"); + navItems.put("Item4", "javascript:alert(document.cookie)"); + navItems.put("Item5", "ftp://testing"); + + EmissaryNav nav = new EmissaryNav(); + + // insert empty map + nav.setNavItems(Map.of()); + assertTrue(CollectionUtils.isEmpty(nav.getNavItems())); + + nav.setNavItems(navItems); + assertEquals(3, nav.getNavItems().size()); + assertEquals("Item1", nav.getNavItems().get(0).getDisplay()); + assertEquals("/path/to/resource", nav.getNavItems().get(0).getLink()); + assertEquals("Item2", nav.getNavItems().get(1).getDisplay()); + assertEquals("http://testing1.com", nav.getNavItems().get(1).getLink()); + assertEquals("Item3", nav.getNavItems().get(2).getDisplay()); + assertEquals("https://testing2.com", nav.getNavItems().get(2).getLink()); + } + +}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/NationalSecurityAgency/emissary/pull/1293nvdPatchWEB
- github.com/NationalSecurityAgency/emissary/security/advisories/GHSA-cpm7-cfpx-3hvpnvdExploitThird Party AdvisoryMitigationWEB
- github.com/advisories/GHSA-cpm7-cfpx-3hvpghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-35571ghsaADVISORY
- github.com/NationalSecurityAgency/emissary/commit/e2078417464b9004620dde28dcbca2f73ea06c13ghsaWEB
News mentions
0No linked articles in our index yet.