Critical severity9.8CISA KEVNVD Advisory· Published Jul 20, 2013· Updated Apr 22, 2026
CVE-2013-2251
CVE-2013-2251
Description
Apache Struts 2.0.0 through 2.3.15 allows remote attackers to execute arbitrary OGNL expressions via a parameter with a crafted (1) action:, (2) redirect:, or (3) redirectAction: prefix.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.struts:struts2-coreMaven | < 2.3.15.1 | 2.3.15.1 |
Affected products
9cpe:2.3:a:fujitsu:interstage_business_process_manager_analytics:12.0:*:*:*:*:*:*:*+ 1 more
- cpe:2.3:a:fujitsu:interstage_business_process_manager_analytics:12.0:*:*:*:*:*:*:*
- cpe:2.3:a:fujitsu:interstage_business_process_manager_analytics:12.1:*:*:*:*:*:*:*
cpe:2.3:a:oracle:siebel_apps_-_e-billing:6.1:*:*:*:*:*:*:*+ 2 more
- cpe:2.3:a:oracle:siebel_apps_-_e-billing:6.1:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:siebel_apps_-_e-billing:6.1.1:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:siebel_apps_-_e-billing:6.2:*:*:*:*:*:*:*
Patches
2630e1ba065a8Merged from STRUTS_2_3_15_X
3 files changed · +48 −69
apps/showcase/src/main/webapp/tags/non-ui/actionPrefix/actionPrefixExample.ftl+3 −7 modified@@ -37,17 +37,13 @@ <@s.textfield label="Enter Some Text" name="text" /> - <@s.submit name="action:actionPrefix" value="%{'action prefix'}" cssClass="btn" /> + <@s.submit action="actionPrefix" value="%{'action prefix'}" cssClass="btn" /> - <@s.submit name="method:alternateMethod" value="%{'method prefix'}" cssClass="btn" /> - - <@s.submit name="redirect:http://www.google.com" value="%{'redirect prefix'}" cssClass="btn" /> - - <@s.submit name="redirect-action:redirectActionPrefix" value="%{'redirect-action prefix'}" cssClass="btn" /> + <@s.submit method="alternateMethod" value="%{'method prefix'}" cssClass="btn" /> <@s.submit value="Normal Submit" cssClass="btn" /> - <@s.submit name="action:redirectActionPrefixAction" value="%{'redirect-action without prefix'}" cssClass="btn" /> + <@s.submit action="redirectActionPrefixAction" value="%{'redirectAction without prefix'}" cssClass="btn" /> </@s.form> </div>
core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java+8 −31 modified@@ -33,11 +33,15 @@ import org.apache.struts2.RequestUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsConstants; -import org.apache.struts2.dispatcher.ServletRedirectResult; import org.apache.struts2.util.PrefixTrie; import javax.servlet.http.HttpServletRequest; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** @@ -164,8 +168,6 @@ public class DefaultActionMapper implements ActionMapper { protected static final String METHOD_PREFIX = "method:"; protected static final String ACTION_PREFIX = "action:"; - protected static final String REDIRECT_PREFIX = "redirect:"; - protected static final String REDIRECT_ACTION_PREFIX = "redirectAction:"; protected boolean allowDynamicMethodCalls = true; protected boolean allowSlashesInActionNames = false; @@ -186,8 +188,7 @@ public DefaultActionMapper() { put(METHOD_PREFIX, new ParameterAction() { public void execute(String key, ActionMapping mapping) { if (allowDynamicMethodCalls) { - mapping.setMethod(key.substring( - METHOD_PREFIX.length())); + mapping.setMethod(key.substring(METHOD_PREFIX.length())); } } }); @@ -203,34 +204,10 @@ public void execute(String key, ActionMapping mapping) { name = name.substring(0, bang); } } - mapping.setName(name); + mapping.setName(cleanupActionName(name)); } }); - put(REDIRECT_PREFIX, new ParameterAction() { - public void execute(String key, ActionMapping mapping) { - ServletRedirectResult redirect = new ServletRedirectResult(); - container.inject(redirect); - redirect.setLocation(key.substring(REDIRECT_PREFIX - .length())); - mapping.setResult(redirect); - } - }); - - put(REDIRECT_ACTION_PREFIX, new ParameterAction() { - public void execute(String key, ActionMapping mapping) { - String location = key.substring(REDIRECT_ACTION_PREFIX - .length()); - ServletRedirectResult redirect = new ServletRedirectResult(); - container.inject(redirect); - String extension = getDefaultExtension(); - if (extension != null && extension.length() > 0) { - location += "." + extension; - } - redirect.setLocation(location); - mapping.setResult(redirect); - } - }); } }; }
core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java+37 −31 modified@@ -21,21 +21,17 @@ package org.apache.struts2.dispatcher.mapper; -import com.mockobjects.dynamic.Mock; import com.mockobjects.servlet.MockHttpServletRequest; import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.Result; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.ConfigurationManager; import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.config.impl.DefaultConfiguration; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsTestCase; -import org.apache.struts2.dispatcher.ServletRedirectResult; import org.apache.struts2.dispatcher.StrutsResultSupport; import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest; -import org.apache.struts2.views.jsp.StrutsMockHttpServletResponse; import java.util.Arrays; import java.util.HashMap; @@ -447,7 +443,7 @@ public void testActionPrefix_fromIEImageButton() throws Exception { public void testRedirectPrefix() throws Exception { Map parameterMap = new HashMap(); - parameterMap.put(DefaultActionMapper.REDIRECT_PREFIX + "http://www.google.com", ""); + parameterMap.put("redirect:" + "http://www.google.com", ""); StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); request.setupGetServletPath("/someServletPath.action"); @@ -458,25 +454,28 @@ public void testRedirectPrefix() throws Exception { ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); Result result = actionMapping.getResult(); - assertNotNull(result); - assertTrue(result instanceof ServletRedirectResult); - - Mock invMock = new Mock(ActionInvocation.class); - ActionInvocation inv = (ActionInvocation) invMock.proxy(); - ActionContext ctx = ActionContext.getContext(); - ctx.put(ServletActionContext.HTTP_REQUEST, request); - StrutsMockHttpServletResponse response = new StrutsMockHttpServletResponse(); - ctx.put(ServletActionContext.HTTP_RESPONSE, response); - invMock.expectAndReturn("getInvocationContext", ctx); - invMock.expectAndReturn("getStack", ctx.getValueStack()); - result.execute(inv); - assertEquals("http://www.google.com", response.getRedirectURL()); - //TODO: need to test location but there's noaccess to the property/method, unless we use reflection + assertNull(result); + } + + public void testUnsafeRedirectPrefix() throws Exception { + Map parameterMap = new HashMap(); + parameterMap.put("redirect:" + "http://%{3*4}", ""); + + StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); + request.setupGetServletPath("/someServletPath.action"); + request.setParameterMap(parameterMap); + + DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); + defaultActionMapper.setContainer(container); + ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); + + Result result = actionMapping.getResult(); + assertNull(result); } public void testRedirectActionPrefix() throws Exception { Map parameterMap = new HashMap(); - parameterMap.put(DefaultActionMapper.REDIRECT_ACTION_PREFIX + "myAction", ""); + parameterMap.put("redirectAction:" + "myAction", ""); StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); request.setupGetServletPath("/someServletPath.action"); @@ -488,17 +487,29 @@ public void testRedirectActionPrefix() throws Exception { StrutsResultSupport result = (StrutsResultSupport) actionMapping.getResult(); - assertNotNull(result); - assertTrue(result instanceof ServletRedirectResult); + assertNull(result); + } - assertEquals("myAction.action", result.getLocation()); + public void testUnsafeRedirectActionPrefix() throws Exception { + Map parameterMap = new HashMap(); + parameterMap.put("redirectAction:" + "%{3*4}", ""); - // TODO: need to test location but there's noaccess to the property/method, unless we use reflection + StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); + request.setupGetServletPath("/someServletPath.action"); + request.setParameterMap(parameterMap); + + DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); + defaultActionMapper.setContainer(container); + ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); + + + StrutsResultSupport result = (StrutsResultSupport) actionMapping.getResult(); + assertNull(result); } public void testRedirectActionPrefixWithEmptyExtension() throws Exception { Map parameterMap = new HashMap(); - parameterMap.put(DefaultActionMapper.REDIRECT_ACTION_PREFIX + "myAction", ""); + parameterMap.put("redirectAction:" + "myAction", ""); StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); request.setupGetServletPath("/someServletPath"); @@ -511,12 +522,7 @@ public void testRedirectActionPrefixWithEmptyExtension() throws Exception { StrutsResultSupport result = (StrutsResultSupport) actionMapping.getResult(); - assertNotNull(result); - assertTrue(result instanceof ServletRedirectResult); - - assertEquals("myAction", result.getLocation()); - - // TODO: need to test location but there's noaccess to the property/method, unless we use reflection + assertNull(result); } public void testCustomActionPrefix() throws Exception {
3 files changed · +48 −69
apps/showcase/src/main/webapp/tags/non-ui/actionPrefix/actionPrefixExample.ftl+3 −7 modified@@ -37,17 +37,13 @@ <@s.textfield label="Enter Some Text" name="text" /> - <@s.submit name="action:actionPrefix" value="%{'action prefix'}" cssClass="btn" /> + <@s.submit action="actionPrefix" value="%{'action prefix'}" cssClass="btn" /> - <@s.submit name="method:alternateMethod" value="%{'method prefix'}" cssClass="btn" /> - - <@s.submit name="redirect:http://www.google.com" value="%{'redirect prefix'}" cssClass="btn" /> - - <@s.submit name="redirect-action:redirectActionPrefix" value="%{'redirect-action prefix'}" cssClass="btn" /> + <@s.submit method="alternateMethod" value="%{'method prefix'}" cssClass="btn" /> <@s.submit value="Normal Submit" cssClass="btn" /> - <@s.submit name="action:redirectActionPrefixAction" value="%{'redirect-action without prefix'}" cssClass="btn" /> + <@s.submit action="redirectActionPrefixAction" value="%{'redirectAction without prefix'}" cssClass="btn" /> </@s.form> </div>
core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java+8 −31 modified@@ -33,11 +33,15 @@ import org.apache.struts2.RequestUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsConstants; -import org.apache.struts2.dispatcher.ServletRedirectResult; import org.apache.struts2.util.PrefixTrie; import javax.servlet.http.HttpServletRequest; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** @@ -164,8 +168,6 @@ public class DefaultActionMapper implements ActionMapper { protected static final String METHOD_PREFIX = "method:"; protected static final String ACTION_PREFIX = "action:"; - protected static final String REDIRECT_PREFIX = "redirect:"; - protected static final String REDIRECT_ACTION_PREFIX = "redirectAction:"; protected boolean allowDynamicMethodCalls = true; protected boolean allowSlashesInActionNames = false; @@ -186,8 +188,7 @@ public DefaultActionMapper() { put(METHOD_PREFIX, new ParameterAction() { public void execute(String key, ActionMapping mapping) { if (allowDynamicMethodCalls) { - mapping.setMethod(key.substring( - METHOD_PREFIX.length())); + mapping.setMethod(key.substring(METHOD_PREFIX.length())); } } }); @@ -203,34 +204,10 @@ public void execute(String key, ActionMapping mapping) { name = name.substring(0, bang); } } - mapping.setName(name); + mapping.setName(cleanupActionName(name)); } }); - put(REDIRECT_PREFIX, new ParameterAction() { - public void execute(String key, ActionMapping mapping) { - ServletRedirectResult redirect = new ServletRedirectResult(); - container.inject(redirect); - redirect.setLocation(key.substring(REDIRECT_PREFIX - .length())); - mapping.setResult(redirect); - } - }); - - put(REDIRECT_ACTION_PREFIX, new ParameterAction() { - public void execute(String key, ActionMapping mapping) { - String location = key.substring(REDIRECT_ACTION_PREFIX - .length()); - ServletRedirectResult redirect = new ServletRedirectResult(); - container.inject(redirect); - String extension = getDefaultExtension(); - if (extension != null && extension.length() > 0) { - location += "." + extension; - } - redirect.setLocation(location); - mapping.setResult(redirect); - } - }); } }; }
core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java+37 −31 modified@@ -21,21 +21,17 @@ package org.apache.struts2.dispatcher.mapper; -import com.mockobjects.dynamic.Mock; import com.mockobjects.servlet.MockHttpServletRequest; import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.Result; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.ConfigurationManager; import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.config.impl.DefaultConfiguration; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsTestCase; -import org.apache.struts2.dispatcher.ServletRedirectResult; import org.apache.struts2.dispatcher.StrutsResultSupport; import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest; -import org.apache.struts2.views.jsp.StrutsMockHttpServletResponse; import java.util.Arrays; import java.util.HashMap; @@ -447,7 +443,7 @@ public void testActionPrefix_fromIEImageButton() throws Exception { public void testRedirectPrefix() throws Exception { Map parameterMap = new HashMap(); - parameterMap.put(DefaultActionMapper.REDIRECT_PREFIX + "http://www.google.com", ""); + parameterMap.put("redirect:" + "http://www.google.com", ""); StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); request.setupGetServletPath("/someServletPath.action"); @@ -458,25 +454,28 @@ public void testRedirectPrefix() throws Exception { ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); Result result = actionMapping.getResult(); - assertNotNull(result); - assertTrue(result instanceof ServletRedirectResult); - - Mock invMock = new Mock(ActionInvocation.class); - ActionInvocation inv = (ActionInvocation) invMock.proxy(); - ActionContext ctx = ActionContext.getContext(); - ctx.put(ServletActionContext.HTTP_REQUEST, request); - StrutsMockHttpServletResponse response = new StrutsMockHttpServletResponse(); - ctx.put(ServletActionContext.HTTP_RESPONSE, response); - invMock.expectAndReturn("getInvocationContext", ctx); - invMock.expectAndReturn("getStack", ctx.getValueStack()); - result.execute(inv); - assertEquals("http://www.google.com", response.getRedirectURL()); - //TODO: need to test location but there's noaccess to the property/method, unless we use reflection + assertNull(result); + } + + public void testUnsafeRedirectPrefix() throws Exception { + Map parameterMap = new HashMap(); + parameterMap.put("redirect:" + "http://%{3*4}", ""); + + StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); + request.setupGetServletPath("/someServletPath.action"); + request.setParameterMap(parameterMap); + + DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); + defaultActionMapper.setContainer(container); + ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); + + Result result = actionMapping.getResult(); + assertNull(result); } public void testRedirectActionPrefix() throws Exception { Map parameterMap = new HashMap(); - parameterMap.put(DefaultActionMapper.REDIRECT_ACTION_PREFIX + "myAction", ""); + parameterMap.put("redirectAction:" + "myAction", ""); StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); request.setupGetServletPath("/someServletPath.action"); @@ -488,17 +487,29 @@ public void testRedirectActionPrefix() throws Exception { StrutsResultSupport result = (StrutsResultSupport) actionMapping.getResult(); - assertNotNull(result); - assertTrue(result instanceof ServletRedirectResult); + assertNull(result); + } - assertEquals("myAction.action", result.getLocation()); + public void testUnsafeRedirectActionPrefix() throws Exception { + Map parameterMap = new HashMap(); + parameterMap.put("redirectAction:" + "%{3*4}", ""); - // TODO: need to test location but there's noaccess to the property/method, unless we use reflection + StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); + request.setupGetServletPath("/someServletPath.action"); + request.setParameterMap(parameterMap); + + DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); + defaultActionMapper.setContainer(container); + ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); + + + StrutsResultSupport result = (StrutsResultSupport) actionMapping.getResult(); + assertNull(result); } public void testRedirectActionPrefixWithEmptyExtension() throws Exception { Map parameterMap = new HashMap(); - parameterMap.put(DefaultActionMapper.REDIRECT_ACTION_PREFIX + "myAction", ""); + parameterMap.put("redirectAction:" + "myAction", ""); StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest(); request.setupGetServletPath("/someServletPath"); @@ -511,12 +522,7 @@ public void testRedirectActionPrefixWithEmptyExtension() throws Exception { StrutsResultSupport result = (StrutsResultSupport) actionMapping.getResult(); - assertNotNull(result); - assertTrue(result instanceof ServletRedirectResult); - - assertEquals("myAction", result.getLocation()); - - // TODO: need to test location but there's noaccess to the property/method, unless we use reflection + assertNull(result); } public void testCustomActionPrefix() throws Exception {
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
22- struts.apache.org/release/2.3.x/docs/s2-016.htmlnvdPatchWEB
- www.oracle.com/technetwork/topics/security/cpujan2014-1972949.htmlnvdPatchThird Party AdvisoryWEB
- www.oracle.com/technetwork/topics/security/cpujul2015-2367936.htmlnvdPatchThird Party AdvisoryWEB
- cxsecurity.com/issue/WLB-2014010087nvdExploitThird Party AdvisoryWEB
- packetstormsecurity.com/files/159629/Apache-Struts-2-Remote-Code-Execution.htmlnvdExploitThird Party AdvisoryVDB EntryWEB
- seclists.org/fulldisclosure/2013/Oct/96nvdExploitMailing ListThird Party AdvisoryWEB
- seclists.org/oss-sec/2014/q1/89nvdMailing ListThird Party AdvisoryWEB
- tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20131023-struts2nvdThird Party AdvisoryWEB
- www.fujitsu.com/global/support/software/security/products-f/interstage-bpm-analytics-201301e.htmlnvdThird Party AdvisoryBroken LinkWEB
- www.securityfocus.com/bid/61189nvdBroken LinkThird Party AdvisoryVDB Entry
- www.securityfocus.com/bid/64758nvdBroken LinkThird Party AdvisoryVDB Entry
- www.securitytracker.com/id/1029184nvdBroken LinkThird Party AdvisoryVDB Entry
- www.securitytracker.com/id/1032916nvdBroken LinkThird Party AdvisoryVDB Entry
- exchange.xforce.ibmcloud.com/vulnerabilities/90392nvdThird Party AdvisoryVDB EntryWEB
- github.com/advisories/GHSA-47qp-8v9g-39hpghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2013-2251ghsaADVISORY
- archiva.apache.org/security.htmlnvdProductWEB
- osvdb.org/98445nvdBroken Link
- github.com/apache/struts/commit/3cfe34fefedcf0fdcfcb061c0aea34a715b7de6ghsaWEB
- github.com/apache/struts/commit/630e1ba065a8215c4e9ac03bfb09be9d655c2b6eghsaWEB
- issues.apache.org/jira/browse/WW-4140ghsaWEB
- www.cisa.gov/known-exploited-vulnerabilities-catalognvdUS Government ResourceWEB
News mentions
0No linked articles in our index yet.