High severityNVD Advisory· Published Sep 30, 2013· Updated Apr 29, 2026
CVE-2013-4316
CVE-2013-4316
Description
Apache Struts 2.0.0 through 2.3.15.1 enables Dynamic Method Invocation by default, which has unknown impact and attack vectors.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.struts:struts2-coreMaven | >= 2.0.0, < 2.3.15.2 | 2.3.15.2 |
org.apache.struts:struts2-rest-pluginMaven | >= 2.0.0, < 2.3.15.2 | 2.3.15.2 |
Affected products
55cpe:2.3:a:apache:struts:2.0.0:*:*:*:*:*:*:*+ 44 more
- cpe:2.3:a:apache:struts:2.0.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.10:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.11:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.11.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.11.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.12:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.13:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.14:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.6:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.7:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.8:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.0.9:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.6:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.8:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.1.8.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.2.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.2.1.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.2.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.2.3.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.1.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.1.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.12:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.14:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.14.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.14.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.14.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.15:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.15.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.4.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.7:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.8:*:*:*:*:*:*:*
cpe:2.3:a:oracle:flexcube_private_banking:12.0.1:*:*:*:*:*:*:*+ 6 more
- cpe:2.3:a:oracle:flexcube_private_banking:12.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:flexcube_private_banking:12.0.2:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:flexcube_private_banking:1.7:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:flexcube_private_banking:2.0:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:flexcube_private_banking:2.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:flexcube_private_banking:2.2.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:flexcube_private_banking:3.0:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:mysql_enterprise_monitor:*:*:*:*:*:*:*:*Range: <=2.3.14
cpe:2.3:a:oracle:webcenter_sites:11.1.1.6.1:*:*:*:*:*:*:*+ 1 more
- cpe:2.3:a:oracle:webcenter_sites:11.1.1.6.1:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:webcenter_sites:11.1.1.8.0:*:*:*:*:*:*:*
Patches
2c643336945ddMerged from STRUTS_2_3_15_1_X - Disables DMI [from revision 1524296]
9 files changed · +59 −32
core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java+24 −13 modified@@ -1,4 +1,5 @@ /* + * $Id$ * $Id$ * * Licensed to the Apache Software Foundation (ASF) under one @@ -33,6 +34,7 @@ import org.apache.struts2.RequestUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsConstants; +import org.apache.struts2.dispatcher.ServletDispatcherResult; import org.apache.struts2.util.PrefixTrie; import javax.servlet.http.HttpServletRequest; @@ -168,8 +170,9 @@ public class DefaultActionMapper implements ActionMapper { protected static final String METHOD_PREFIX = "method:"; protected static final String ACTION_PREFIX = "action:"; + private static final String STRUTS2_ACTION_PREFIX_PARSED = "_struts2_action_prefix_parsed"; - protected boolean allowDynamicMethodCalls = true; + protected boolean allowDynamicMethodCalls = false; protected boolean allowSlashesInActionNames = false; protected boolean alwaysSelectFullNamespace = false; protected PrefixTrie prefixTrie = null; @@ -186,25 +189,33 @@ public DefaultActionMapper() { prefixTrie = new PrefixTrie() { { put(METHOD_PREFIX, new ParameterAction() { - public void execute(String key, ActionMapping mapping) { + public void execute(String key, ActionMapping mapping, HttpServletRequest request) { if (allowDynamicMethodCalls) { mapping.setMethod(key.substring(METHOD_PREFIX.length())); } } }); put(ACTION_PREFIX, new ParameterAction() { - public void execute(String key, ActionMapping mapping) { - String name = key.substring(ACTION_PREFIX.length()); - if (allowDynamicMethodCalls) { - int bang = name.indexOf('!'); - if (bang != -1) { - String method = name.substring(bang + 1); - mapping.setMethod(method); - name = name.substring(0, bang); + public void execute(final String key, ActionMapping mapping, HttpServletRequest request) { + if (request != null && request.getAttribute(STRUTS2_ACTION_PREFIX_PARSED) == null) { + request.setAttribute(STRUTS2_ACTION_PREFIX_PARSED, true); + String name = key.substring(ACTION_PREFIX.length()); + if (allowDynamicMethodCalls) { + int bang = name.indexOf('!'); + if (bang != -1) { + String method = name.substring(bang + 1); + mapping.setMethod(method); + name = name.substring(0, bang); + } + } + String actionName = cleanupActionName(name); + mapping.setName(actionName); + if (getDefaultExtension() != null) { + actionName = actionName + "." + getDefaultExtension(); } + mapping.setResult(new ServletDispatcherResult(actionName)); } - mapping.setName(cleanupActionName(name)); } }); @@ -225,7 +236,7 @@ protected void addParameterAction(String prefix, ParameterAction parameterAction @Inject(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION) public void setAllowDynamicMethodCalls(String allow) { - allowDynamicMethodCalls = "true".equals(allow); + allowDynamicMethodCalls = "true".equalsIgnoreCase(allow); } @Inject(StrutsConstants.STRUTS_ENABLE_SLASHES_IN_ACTION_NAMES) @@ -335,7 +346,7 @@ public void handleSpecialParameters(HttpServletRequest request, ActionMapping ma if (!uniqueParameters.contains(key)) { ParameterAction parameterAction = (ParameterAction) prefixTrie.get(key); if (parameterAction != null) { - parameterAction.execute(key, mapping); + parameterAction.execute(key, mapping, request); uniqueParameters.add(key); break; }
core/src/main/java/org/apache/struts2/dispatcher/mapper/ParameterAction.java+3 −1 modified@@ -21,6 +21,8 @@ package org.apache.struts2.dispatcher.mapper; +import javax.servlet.http.HttpServletRequest; + /** * Defines a parameter action prefix. This is executed when the configured prefix key is matched in a parameter * name, allowing the implementation to manipulate the action mapping accordingly. For example, if the "action:foo" @@ -30,5 +32,5 @@ * @since 2.1.0 */ public interface ParameterAction { - void execute(String key, ActionMapping mapping); + void execute(String key, ActionMapping mapping, HttpServletRequest request); }
core/src/main/resources/org/apache/struts2/default.properties+1 −1 modified@@ -105,7 +105,7 @@ struts.serve.static.browserCache=true ### like method:bar (but not action:foo). ### An alternative to implicit dynamic method invocation is to use wildcard ### mappings, such as <action name="*/*" method="{2}" class="actions.{1}"> -struts.enable.DynamicMethodInvocation = true +struts.enable.DynamicMethodInvocation = false ### Set this to true if you wish to allow slashes in your action names. If false, ### Actions names cannot have slashes, and will be accessible via any directory
core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java+9 −5 modified@@ -1,4 +1,5 @@ /* + * $Id$ * $Id$ * * Licensed to the Apache Software Foundation (ASF) under one @@ -33,6 +34,7 @@ import org.apache.struts2.dispatcher.StrutsResultSupport; import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest; +import javax.servlet.http.HttpServletRequest; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -88,6 +90,7 @@ public void testGetMappingWithMethod() throws Exception { req.addExpectedGetAttributeName("javax.servlet.include.servlet_path"); DefaultActionMapper mapper = new DefaultActionMapper(); + mapper.setAllowDynamicMethodCalls("true"); ActionMapping mapping = mapper.getMapping(req, configManager); assertEquals("/my/namespace", mapping.getNamespace()); @@ -212,6 +215,7 @@ public void testGetMappingWithUnknownNamespaceButFullNamespaceSelect() throws Ex public void testGetMappingWithActionName_methodAndName() throws Exception { DefaultActionMapper mapper = new DefaultActionMapper(); + mapper.setAllowDynamicMethodCalls("true"); ActionMapping mapping = mapper.getMappingFromActionName("actionName!add"); assertEquals("actionName", mapping.getName()); assertEquals("add", mapping.getMethod()); @@ -407,7 +411,7 @@ public void testActionPrefix() throws Exception { DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); - assertEquals(actionMapping.getName(), "myAction"); + assertEquals("myAction", actionMapping.getName()); } public void testActionPrefix_fromImageButton() throws Exception { @@ -423,7 +427,7 @@ public void testActionPrefix_fromImageButton() throws Exception { DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); - assertEquals(actionMapping.getName(), "myAction"); + assertEquals("myAction", actionMapping.getName()); } public void testActionPrefix_fromIEImageButton() throws Exception { @@ -438,7 +442,7 @@ public void testActionPrefix_fromIEImageButton() throws Exception { DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); - assertEquals(actionMapping.getName(), "myAction"); + assertEquals("myAction", actionMapping.getName()); } public void testRedirectPrefix() throws Exception { @@ -529,13 +533,13 @@ public void testCustomActionPrefix() throws Exception { Map parameterMap = new HashMap(); parameterMap.put("foo:myAction", ""); - StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); + final StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); request.setParameterMap(parameterMap); request.setupGetServletPath("/someServletPath.action"); DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); defaultActionMapper.addParameterAction("foo", new ParameterAction() { - public void execute(String key, ActionMapping mapping) { + public void execute(String key, ActionMapping mapping, HttpServletRequest request) { mapping.setName("myAction"); } });
core/src/test/java/org/apache/struts2/dispatcher/mapper/Restful2ActionMapperTest.java+1 −0 modified@@ -92,6 +92,7 @@ public void testGetId() throws Exception { public void testGetEdit() throws Exception { mapper.setIdParameterName("id"); + mapper.setAllowDynamicMethodCalls("true"); req.setupGetRequestURI("/my/namespace/foo/3!edit"); req.setupGetServletPath("/my/namespace/foo/3!edit"); req.setupGetAttribute(null);
core/src/test/java/org/apache/struts2/views/jsp/ActionTagTest.java+12 −11 modified@@ -21,24 +21,24 @@ package org.apache.struts2.views.jsp; -import java.util.HashMap; - -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.PageContext; - +import com.mockobjects.dynamic.Mock; +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ActionProxy; +import com.opensymphony.xwork2.config.entities.ActionConfig; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsException; import org.apache.struts2.TestAction; import org.apache.struts2.TestActionTagResult; import org.apache.struts2.TestConfigurationProvider; import org.apache.struts2.components.ActionComponent; +import org.apache.struts2.dispatcher.mapper.ActionMapper; +import org.apache.struts2.dispatcher.mapper.DefaultActionMapper; -import com.mockobjects.dynamic.Mock; -import com.opensymphony.xwork2.Action; -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ActionProxy; -import com.opensymphony.xwork2.config.entities.ActionConfig; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; +import java.util.HashMap; /** @@ -282,6 +282,7 @@ public void testActionMethodWithExecuteResult() throws Exception { tag.setNamespace(""); tag.setName("testActionTagAction!input"); tag.setExecuteResult(true); + ((DefaultActionMapper)container.getInstance(ActionMapper.class)).setAllowDynamicMethodCalls("true"); tag.doStartTag();
core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java+5 −0 modified@@ -39,6 +39,8 @@ import org.apache.struts2.TestConfigurationProvider; import org.apache.struts2.components.Form; import org.apache.struts2.dispatcher.Dispatcher; +import org.apache.struts2.dispatcher.mapper.ActionMapper; +import org.apache.struts2.dispatcher.mapper.DefaultActionMapper; import org.apache.struts2.views.jsp.AbstractUITagTest; import org.apache.struts2.views.jsp.ActionTag; import org.easymock.EasyMock; @@ -110,6 +112,9 @@ public void testFormWithActionAttributeContainingBothActionAndDMIMethod() throws tag.setEnctype("myEncType"); tag.setTitle("mytitle"); tag.setOnsubmit("submitMe()"); + + ((DefaultActionMapper)container.getInstance(ActionMapper.class)).setAllowDynamicMethodCalls("true"); + tag.doStartTag(); tag.doEndTag();
plugins/rest/src/main/java/org/apache/struts2/rest/RestActionMapper.java+1 −1 modified@@ -108,7 +108,7 @@ public class RestActionMapper extends DefaultActionMapper { private String optionsMethodName = "options"; private String postContinueMethodName = "createContinue"; private String putContinueMethodName = "updateContinue"; - private boolean allowDynamicMethodCalls = true; + private boolean allowDynamicMethodCalls = false; public RestActionMapper() { }
plugins/rest/src/test/java/org/apache/struts2/rest/RestActionMapperTest.java+3 −0 modified@@ -200,6 +200,7 @@ public void testShouldAllowExclamation() throws Exception { req.setServletPath("/animals/dog/fido!edit"); req.setMethod("GET"); + mapper.setAllowDynamicMethodCalls("true"); ActionMapping mapping = mapper.getMapping(req, configManager); assertEquals("/animals", mapping.getNamespace()); @@ -303,6 +304,8 @@ public void testDynamicMethodInvocation() throws Exception { req.setServletPath("/animals/dog/23!edit"); req.setMethod("GET"); + mapper.setAllowDynamicMethodCalls("true"); + // when ActionMapping actionMapping = mapper.getMapping(req, configManager);
9 files changed · +59 −32
core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java+24 −13 modified@@ -1,4 +1,5 @@ /* + * $Id$ * $Id$ * * Licensed to the Apache Software Foundation (ASF) under one @@ -33,6 +34,7 @@ import org.apache.struts2.RequestUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsConstants; +import org.apache.struts2.dispatcher.ServletDispatcherResult; import org.apache.struts2.util.PrefixTrie; import javax.servlet.http.HttpServletRequest; @@ -168,8 +170,9 @@ public class DefaultActionMapper implements ActionMapper { protected static final String METHOD_PREFIX = "method:"; protected static final String ACTION_PREFIX = "action:"; + private static final String STRUTS2_ACTION_PREFIX_PARSED = "_struts2_action_prefix_parsed"; - protected boolean allowDynamicMethodCalls = true; + protected boolean allowDynamicMethodCalls = false; protected boolean allowSlashesInActionNames = false; protected boolean alwaysSelectFullNamespace = false; protected PrefixTrie prefixTrie = null; @@ -186,25 +189,33 @@ public DefaultActionMapper() { prefixTrie = new PrefixTrie() { { put(METHOD_PREFIX, new ParameterAction() { - public void execute(String key, ActionMapping mapping) { + public void execute(String key, ActionMapping mapping, HttpServletRequest request) { if (allowDynamicMethodCalls) { mapping.setMethod(key.substring(METHOD_PREFIX.length())); } } }); put(ACTION_PREFIX, new ParameterAction() { - public void execute(String key, ActionMapping mapping) { - String name = key.substring(ACTION_PREFIX.length()); - if (allowDynamicMethodCalls) { - int bang = name.indexOf('!'); - if (bang != -1) { - String method = name.substring(bang + 1); - mapping.setMethod(method); - name = name.substring(0, bang); + public void execute(final String key, ActionMapping mapping, HttpServletRequest request) { + if (request != null && request.getAttribute(STRUTS2_ACTION_PREFIX_PARSED) == null) { + request.setAttribute(STRUTS2_ACTION_PREFIX_PARSED, true); + String name = key.substring(ACTION_PREFIX.length()); + if (allowDynamicMethodCalls) { + int bang = name.indexOf('!'); + if (bang != -1) { + String method = name.substring(bang + 1); + mapping.setMethod(method); + name = name.substring(0, bang); + } + } + String actionName = cleanupActionName(name); + mapping.setName(actionName); + if (getDefaultExtension() != null) { + actionName = actionName + "." + getDefaultExtension(); } + mapping.setResult(new ServletDispatcherResult(actionName)); } - mapping.setName(cleanupActionName(name)); } }); @@ -225,7 +236,7 @@ protected void addParameterAction(String prefix, ParameterAction parameterAction @Inject(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION) public void setAllowDynamicMethodCalls(String allow) { - allowDynamicMethodCalls = "true".equals(allow); + allowDynamicMethodCalls = "true".equalsIgnoreCase(allow); } @Inject(StrutsConstants.STRUTS_ENABLE_SLASHES_IN_ACTION_NAMES) @@ -335,7 +346,7 @@ public void handleSpecialParameters(HttpServletRequest request, ActionMapping ma if (!uniqueParameters.contains(key)) { ParameterAction parameterAction = (ParameterAction) prefixTrie.get(key); if (parameterAction != null) { - parameterAction.execute(key, mapping); + parameterAction.execute(key, mapping, request); uniqueParameters.add(key); break; }
core/src/main/java/org/apache/struts2/dispatcher/mapper/ParameterAction.java+3 −1 modified@@ -21,6 +21,8 @@ package org.apache.struts2.dispatcher.mapper; +import javax.servlet.http.HttpServletRequest; + /** * Defines a parameter action prefix. This is executed when the configured prefix key is matched in a parameter * name, allowing the implementation to manipulate the action mapping accordingly. For example, if the "action:foo" @@ -30,5 +32,5 @@ * @since 2.1.0 */ public interface ParameterAction { - void execute(String key, ActionMapping mapping); + void execute(String key, ActionMapping mapping, HttpServletRequest request); }
core/src/main/resources/org/apache/struts2/default.properties+1 −1 modified@@ -105,7 +105,7 @@ struts.serve.static.browserCache=true ### like method:bar (but not action:foo). ### An alternative to implicit dynamic method invocation is to use wildcard ### mappings, such as <action name="*/*" method="{2}" class="actions.{1}"> -struts.enable.DynamicMethodInvocation = true +struts.enable.DynamicMethodInvocation = false ### Set this to true if you wish to allow slashes in your action names. If false, ### Actions names cannot have slashes, and will be accessible via any directory
core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java+9 −5 modified@@ -1,4 +1,5 @@ /* + * $Id$ * $Id$ * * Licensed to the Apache Software Foundation (ASF) under one @@ -33,6 +34,7 @@ import org.apache.struts2.dispatcher.StrutsResultSupport; import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest; +import javax.servlet.http.HttpServletRequest; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -88,6 +90,7 @@ public void testGetMappingWithMethod() throws Exception { req.addExpectedGetAttributeName("javax.servlet.include.servlet_path"); DefaultActionMapper mapper = new DefaultActionMapper(); + mapper.setAllowDynamicMethodCalls("true"); ActionMapping mapping = mapper.getMapping(req, configManager); assertEquals("/my/namespace", mapping.getNamespace()); @@ -212,6 +215,7 @@ public void testGetMappingWithUnknownNamespaceButFullNamespaceSelect() throws Ex public void testGetMappingWithActionName_methodAndName() throws Exception { DefaultActionMapper mapper = new DefaultActionMapper(); + mapper.setAllowDynamicMethodCalls("true"); ActionMapping mapping = mapper.getMappingFromActionName("actionName!add"); assertEquals("actionName", mapping.getName()); assertEquals("add", mapping.getMethod()); @@ -407,7 +411,7 @@ public void testActionPrefix() throws Exception { DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); - assertEquals(actionMapping.getName(), "myAction"); + assertEquals("myAction", actionMapping.getName()); } public void testActionPrefix_fromImageButton() throws Exception { @@ -423,7 +427,7 @@ public void testActionPrefix_fromImageButton() throws Exception { DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); - assertEquals(actionMapping.getName(), "myAction"); + assertEquals("myAction", actionMapping.getName()); } public void testActionPrefix_fromIEImageButton() throws Exception { @@ -438,7 +442,7 @@ public void testActionPrefix_fromIEImageButton() throws Exception { DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); - assertEquals(actionMapping.getName(), "myAction"); + assertEquals("myAction", actionMapping.getName()); } public void testRedirectPrefix() throws Exception { @@ -529,13 +533,13 @@ public void testCustomActionPrefix() throws Exception { Map parameterMap = new HashMap(); parameterMap.put("foo:myAction", ""); - StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); + final StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); request.setParameterMap(parameterMap); request.setupGetServletPath("/someServletPath.action"); DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); defaultActionMapper.addParameterAction("foo", new ParameterAction() { - public void execute(String key, ActionMapping mapping) { + public void execute(String key, ActionMapping mapping, HttpServletRequest request) { mapping.setName("myAction"); } });
core/src/test/java/org/apache/struts2/dispatcher/mapper/Restful2ActionMapperTest.java+1 −0 modified@@ -92,6 +92,7 @@ public void testGetId() throws Exception { public void testGetEdit() throws Exception { mapper.setIdParameterName("id"); + mapper.setAllowDynamicMethodCalls("true"); req.setupGetRequestURI("/my/namespace/foo/3!edit"); req.setupGetServletPath("/my/namespace/foo/3!edit"); req.setupGetAttribute(null);
core/src/test/java/org/apache/struts2/views/jsp/ActionTagTest.java+12 −11 modified@@ -21,24 +21,24 @@ package org.apache.struts2.views.jsp; -import java.util.HashMap; - -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.PageContext; - +import com.mockobjects.dynamic.Mock; +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ActionProxy; +import com.opensymphony.xwork2.config.entities.ActionConfig; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsException; import org.apache.struts2.TestAction; import org.apache.struts2.TestActionTagResult; import org.apache.struts2.TestConfigurationProvider; import org.apache.struts2.components.ActionComponent; +import org.apache.struts2.dispatcher.mapper.ActionMapper; +import org.apache.struts2.dispatcher.mapper.DefaultActionMapper; -import com.mockobjects.dynamic.Mock; -import com.opensymphony.xwork2.Action; -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ActionProxy; -import com.opensymphony.xwork2.config.entities.ActionConfig; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; +import java.util.HashMap; /** @@ -282,6 +282,7 @@ public void testActionMethodWithExecuteResult() throws Exception { tag.setNamespace(""); tag.setName("testActionTagAction!input"); tag.setExecuteResult(true); + ((DefaultActionMapper)container.getInstance(ActionMapper.class)).setAllowDynamicMethodCalls("true"); tag.doStartTag();
core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java+5 −0 modified@@ -39,6 +39,8 @@ import org.apache.struts2.TestConfigurationProvider; import org.apache.struts2.components.Form; import org.apache.struts2.dispatcher.Dispatcher; +import org.apache.struts2.dispatcher.mapper.ActionMapper; +import org.apache.struts2.dispatcher.mapper.DefaultActionMapper; import org.apache.struts2.views.jsp.AbstractUITagTest; import org.apache.struts2.views.jsp.ActionTag; import org.easymock.EasyMock; @@ -110,6 +112,9 @@ public void testFormWithActionAttributeContainingBothActionAndDMIMethod() throws tag.setEnctype("myEncType"); tag.setTitle("mytitle"); tag.setOnsubmit("submitMe()"); + + ((DefaultActionMapper)container.getInstance(ActionMapper.class)).setAllowDynamicMethodCalls("true"); + tag.doStartTag(); tag.doEndTag();
plugins/rest/src/main/java/org/apache/struts2/rest/RestActionMapper.java+1 −1 modified@@ -108,7 +108,7 @@ public class RestActionMapper extends DefaultActionMapper { private String optionsMethodName = "options"; private String postContinueMethodName = "createContinue"; private String putContinueMethodName = "updateContinue"; - private boolean allowDynamicMethodCalls = true; + private boolean allowDynamicMethodCalls = false; public RestActionMapper() { }
plugins/rest/src/test/java/org/apache/struts2/rest/RestActionMapperTest.java+3 −0 modified@@ -200,6 +200,7 @@ public void testShouldAllowExclamation() throws Exception { req.setServletPath("/animals/dog/fido!edit"); req.setMethod("GET"); + mapper.setAllowDynamicMethodCalls("true"); ActionMapping mapping = mapper.getMapping(req, configManager); assertEquals("/animals", mapping.getNamespace()); @@ -303,6 +304,8 @@ public void testDynamicMethodInvocation() throws Exception { req.setServletPath("/animals/dog/23!edit"); req.setMethod("GET"); + mapper.setAllowDynamicMethodCalls("true"); + // when ActionMapping actionMapping = mapper.getMapping(req, configManager);
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
9- archives.neohapsis.com/archives/bugtraq/2013-09/0107.htmlnvdPatchWEB
- struts.apache.org/release/2.3.x/docs/s2-019.htmlnvdPatchVendor AdvisoryWEB
- www.oracle.com/technetwork/topics/security/cpujan2014-1972949.htmlnvdThird Party Advisory
- www.securityfocus.com/bid/64758nvdThird Party AdvisoryVDB Entry
- www.securitytracker.com/id/1029078nvdThird Party AdvisoryVDB Entry
- github.com/advisories/GHSA-j7h6-xr7g-m2c5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2013-4316ghsaADVISORY
- github.com/apache/struts/commit/58947c3f85ae641c1a476316a2888e53605948d1ghsaWEB
- github.com/apache/struts/commit/c643336945dda84cbcdc8a39530baa24fede28c4ghsaWEB
News mentions
0No linked articles in our index yet.