High severity7.5NVD Advisory· Published Jul 4, 2016· Updated May 6, 2026
CVE-2016-4433
CVE-2016-4433
Description
Apache Struts 2 2.3.20 through 2.3.28.1 allows remote attackers to bypass intended access restrictions and conduct redirection attacks via a crafted request.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.struts.xwork:xwork-coreMaven | >= 2.3.20, < 2.3.29 | 2.3.29 |
Affected products
7cpe:2.3:a:apache:struts:2.3.20:*:*:*:*:*:*:*+ 6 more
- cpe:2.3:a:apache:struts:2.3.20:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.20.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.20.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.24:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.24.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.24.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:struts:2.3.28:*:*:*:*:*:*:*
Patches
1b28b78c062f0Introduces new callMethod() function to be used to execute actions
3 files changed · +81 −2
xwork-core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java+2 −2 modified@@ -427,13 +427,13 @@ protected String invokeAction(Object action, ActionConfig actionConfig) throws E Object methodResult; try { - methodResult = ognlUtil.getValue(methodName + "()", getStack().getContext(), action); + methodResult = ognlUtil.callMethod(methodName + "()", getStack().getContext(), action); } catch (MethodFailedException e) { // if reason is missing method, try find version with "do" prefix if (e.getReason() instanceof NoSuchMethodException) { try { String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1) + "()"; - methodResult = ognlUtil.getValue(altMethodName, getStack().getContext(), action); + methodResult = ognlUtil.callMethod(altMethodName, getStack().getContext(), action); } catch (MethodFailedException e1) { // if still method doesn't exist, try checking UnknownHandlers if (e1.getReason() instanceof NoSuchMethodException) {
xwork-core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java+64 −0 modified@@ -290,6 +290,9 @@ public Void execute(Object tree) throws OgnlException { if (isEvalExpression(tree, context)) { throw new OgnlException("Eval expression/chained expressions cannot be used as parameter name"); } + if (isArithmeticExpression(tree, context)) { + throw new OgnlException("Arithmetic expressions cannot be used as parameter name"); + } Ognl.setValue(tree, context, root, value); return null; } @@ -309,6 +312,32 @@ private boolean isEvalExpression(Object tree, Map<String, Object> context) throw return false; } + private boolean isArithmeticExpression(Object tree, Map<String, Object> context) throws OgnlException { + if (tree instanceof SimpleNode) { + SimpleNode node = (SimpleNode) tree; + OgnlContext ognlContext = null; + + if (context!=null && context instanceof OgnlContext) { + ognlContext = (OgnlContext) context; + } + return node.isOperation(ognlContext); + } + return false; + } + + private boolean isSimpleMethod(Object tree, Map<String, Object> context) throws OgnlException { + if (tree instanceof SimpleNode) { + SimpleNode node = (SimpleNode) tree; + OgnlContext ognlContext = null; + + if (context!=null && context instanceof OgnlContext) { + ognlContext = (OgnlContext) context; + } + return node.isSimpleMethod(ognlContext) && !node.isChain(ognlContext); + } + return false; + } + public Object getValue(final String name, final Map<String, Object> context, final Object root) throws OgnlException { return compileAndExecute(name, context, new OgnlTask<Object>() { public Object execute(Object tree) throws OgnlException { @@ -317,6 +346,14 @@ public Object execute(Object tree) throws OgnlException { }); } + public Object callMethod(final String name, final Map<String, Object> context, final Object root) throws OgnlException { + return compileAndExecuteMethod(name, context, new OgnlTask<Object>() { + public Object execute(Object tree) throws OgnlException { + return Ognl.getValue(tree, context, root); + } + }); + } + public Object getValue(final String name, final Map<String, Object> context, final Object root, final Class resultType) throws OgnlException { return compileAndExecute(name, context, new OgnlTask<Object>() { public Object execute(Object tree) throws OgnlException { @@ -351,6 +388,27 @@ private <T> Object compileAndExecute(String expression, Map<String, Object> cont return exec; } + private <T> Object compileAndExecuteMethod(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException { + Object tree; + if (enableExpressionCache) { + tree = expressions.get(expression); + if (tree == null) { + tree = Ognl.parseExpression(expression); + checkSimpleMethod(tree, context); + } + } else { + tree = Ognl.parseExpression(expression); + checkSimpleMethod(tree, context); + } + + final T exec = task.execute(tree); + // if cache is enabled and it's a valid expression, puts it in + if(enableExpressionCache) { + expressions.putIfAbsent(expression, tree); + } + return exec; + } + public Object compile(String expression, Map<String, Object> context) throws OgnlException { return compileAndExecute(expression,context,new OgnlTask<Object>() { public Object execute(Object tree) throws OgnlException { @@ -365,6 +423,12 @@ private void checkEnableEvalExpression(Object tree, Map<String, Object> context) } } + private void checkSimpleMethod(Object tree, Map<String, Object> context) throws OgnlException { + if (!isSimpleMethod(tree, context)) { + throw new OgnlException("It isn't a simple method which can be called!"); + } + } + /** * Copies the properties in the object "from" and sets them in the object "to" * using specified type converter, or {@link com.opensymphony.xwork2.conversion.impl.XWorkConverter} if none
xwork-core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java+15 −0 modified@@ -765,6 +765,21 @@ public void testBlockSequenceOfExpressions() throws Exception { assertEquals(expected.getMessage(), "Eval expressions/chained expressions have been disabled!"); } + public void testCallMethod() throws Exception { + Foo foo = new Foo(); + + Exception expected = null; + try { + ognlUtil.callMethod("#booScope=@myclass@DEFAULT_SCOPE,#bootScope.init()", ognlUtil.createDefaultContext(foo), foo); + fail(); + } catch (OgnlException e) { + expected = e; + } + assertNotNull(expected); + assertSame(OgnlException.class, expected.getClass()); + assertEquals(expected.getMessage(), "It isn't a simple method which can be called!"); + } + public static class Email { String address;
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
12- jvn.jp/en/jp/JVN45093481/index.htmlnvdVendor AdvisoryWEB
- jvndb.jvn.jp/jvndb/JVNDB-2016-000112nvdVDB EntryVendor AdvisoryWEB
- www-01.ibm.com/support/docview.wssnvdThird Party AdvisoryWEB
- www-01.ibm.com/support/docview.wssnvdThird Party AdvisoryWEB
- github.com/advisories/GHSA-wm8w-qp2f-728qghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-4433ghsaADVISORY
- struts.apache.org/docs/s2-039.htmlnvdVendor AdvisoryWEB
- www.oracle.com/technetwork/security-advisory/cpujul2017-3236622.htmlnvdWEB
- bugzilla.redhat.com/show_bug.cginvdIssue TrackingWEB
- github.com/apache/struts/commit/b28b78c062f0bf3c79793a25aab8c9b6c12bce6eghsaWEB
- web.archive.org/web/20210123144955/http://www.securityfocus.com/bid/91282ghsaWEB
- www.securityfocus.com/bid/91282nvd
News mentions
0No linked articles in our index yet.