Critical severity9.8NVD Advisory· Published Oct 3, 2016· Updated May 6, 2026
CVE-2016-4436
CVE-2016-4436
Description
Apache Struts 2 before 2.3.29 and 2.5.x before 2.5.1 allow attackers to have unspecified impact via vectors related to improper action name clean up.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.struts:struts2-coreMaven | >= 2.0.0, < 2.3.29 | 2.3.29 |
org.apache.struts:struts2-coreMaven | >= 2.5-BETA1, < 2.5.1 | 2.5.1 |
Patches
2237432512df0Throws away methods that doesn't match pattern
2 files changed · +29 −15
core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java+2 −12 modified@@ -33,6 +33,7 @@ import org.apache.struts2.RequestUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsConstants; +import org.apache.struts2.StrutsException; import org.apache.struts2.util.PrefixTrie; import javax.servlet.http.HttpServletRequest; @@ -384,18 +385,7 @@ protected String cleanupActionName(final String rawActionName) { if (allowedActionNames.matcher(rawActionName).matches()) { return rawActionName; } else { - if (LOG.isWarnEnabled()) { - LOG.warn("Action/method [#0] does not match allowed action names pattern [#1], cleaning it up!", - rawActionName, allowedActionNames); - } - String cleanActionName = rawActionName; - for (String chunk : allowedActionNames.split(rawActionName)) { - cleanActionName = cleanActionName.replace(chunk, ""); - } - if (LOG.isDebugEnabled()) { - LOG.debug("Cleaned action/method name [#0]", cleanActionName); - } - return cleanActionName; + throw new StrutsException("Action [" + rawActionName + "] does not match allowed action names pattern [" + allowedActionNames + "]!"); } }
core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java+27 −3 modified@@ -30,6 +30,7 @@ import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.config.impl.DefaultConfiguration; import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsException; import org.apache.struts2.StrutsInternalTestCase; import org.apache.struts2.dispatcher.StrutsResultSupport; import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest; @@ -844,14 +845,37 @@ public void testAllowedActionNames() throws Exception { String actionName = "action"; assertEquals(actionName, mapper.cleanupActionName(actionName)); + Throwable expected = null; + actionName = "${action}"; - assertEquals("action", mapper.cleanupActionName(actionName)); + try { + mapper.cleanupActionName(actionName); + fail(); + } catch (Throwable t) { + expected = t; + } + assertTrue(expected instanceof StrutsException); + assertEquals("Action [${action}] does not match allowed action names pattern [[a-zA-Z0-9._!/\\-]*]!", expected.getMessage()); actionName = "${${%{action}}}"; - assertEquals("action", mapper.cleanupActionName(actionName)); + try { + mapper.cleanupActionName(actionName); + fail(); + } catch (Throwable t) { + expected = t; + } + assertTrue(expected instanceof StrutsException); + assertEquals("Action [${${%{action}}}] does not match allowed action names pattern [[a-zA-Z0-9._!/\\-]*]!", expected.getMessage()); actionName = "${#foo='action',#foo}"; - assertEquals("fooactionfoo", mapper.cleanupActionName(actionName)); + try { + mapper.cleanupActionName(actionName); + fail(); + } catch (Throwable t) { + expected = t; + } + assertTrue(expected instanceof StrutsException); + assertEquals("Action [${#foo='action',#foo}] does not match allowed action names pattern [[a-zA-Z0-9._!/\\-]*]!", expected.getMessage()); actionName = "test-action"; assertEquals("test-action", mapper.cleanupActionName(actionName));
27ca165ddbf8Throws away methods that doesn't match pattern
2 files changed · +29 −11
core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java+2 −8 modified@@ -34,6 +34,7 @@ import org.apache.struts2.RequestUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsConstants; +import org.apache.struts2.StrutsException; import org.apache.struts2.util.PrefixTrie; import javax.servlet.http.HttpServletRequest; @@ -385,14 +386,7 @@ protected String cleanupActionName(final String rawActionName) { if (allowedActionNames.matcher(rawActionName).matches()) { return rawActionName; } else { - LOG.warn("Action [{}] does not match allowed action names pattern [{}], cleaning it up!", - rawActionName, allowedActionNames); - String cleanActionName = rawActionName; - for (String chunk : allowedActionNames.split(rawActionName)) { - cleanActionName = cleanActionName.replace(chunk, ""); - } - LOG.debug("Cleaned action name [{}]", cleanActionName); - return cleanActionName; + throw new StrutsException("Action [" + rawActionName + "] does not match allowed action names pattern [" + allowedActionNames + "]!"); } }
core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java+27 −3 modified@@ -30,6 +30,7 @@ import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.config.impl.DefaultConfiguration; import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsException; import org.apache.struts2.StrutsInternalTestCase; import org.apache.struts2.result.StrutsResultSupport; import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest; @@ -844,14 +845,37 @@ public void testAllowedActionNames() throws Exception { String actionName = "action"; assertEquals(actionName, mapper.cleanupActionName(actionName)); + Throwable expected = null; + actionName = "${action}"; - assertEquals("action", mapper.cleanupActionName(actionName)); + try { + mapper.cleanupActionName(actionName); + fail(); + } catch (Throwable t) { + expected = t; + } + assertTrue(expected instanceof StrutsException); + assertEquals("Action [${action}] does not match allowed action names pattern [[a-zA-Z0-9._!/\\-]*]!", expected.getMessage()); actionName = "${${%{action}}}"; - assertEquals("action", mapper.cleanupActionName(actionName)); + try { + mapper.cleanupActionName(actionName); + fail(); + } catch (Throwable t) { + expected = t; + } + assertTrue(expected instanceof StrutsException); + assertEquals("Action [${${%{action}}}] does not match allowed action names pattern [[a-zA-Z0-9._!/\\-]*]!", expected.getMessage()); actionName = "${#foo='action',#foo}"; - assertEquals("fooactionfoo", mapper.cleanupActionName(actionName)); + try { + mapper.cleanupActionName(actionName); + fail(); + } catch (Throwable t) { + expected = t; + } + assertTrue(expected instanceof StrutsException); + assertEquals("Action [${#foo='action',#foo}] does not match allowed action names pattern [[a-zA-Z0-9._!/\\-]*]!", expected.getMessage()); actionName = "test-action"; assertEquals("test-action", mapper.cleanupActionName(actionName));
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
10- www-01.ibm.com/support/docview.wssnvdThird Party AdvisoryWEB
- www-01.ibm.com/support/docview.wssnvdThird Party AdvisoryWEB
- www.securityfocus.com/bid/91280nvdThird Party Advisory
- github.com/advisories/GHSA-xm92-v2mq-842qghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-4436ghsaADVISORY
- struts.apache.org/docs/s2-035.htmlnvdVendor AdvisoryWEB
- www.oracle.com/technetwork/security-advisory/cpujul2017-3236622.htmlnvdWEB
- github.com/apache/struts/commit/237432512df0e27013f7c7b9ab59fdce44ca34a5ghsaWEB
- github.com/apache/struts/commit/27ca165ddbf81c84bafbd083b99a18d89cc49ca7ghsaWEB
- web.archive.org/web/20161015140316/http://www.securityfocus.com/bid/91280ghsaWEB
News mentions
0No linked articles in our index yet.