This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch WW-4858-json-parameter-filtering in repository https://gitbox.apache.org/repos/asf/struts.git
commit 77c096080fbec94fefda31edc7d0d066cacef80d Author: Lukasz Lenart <[email protected]> AuthorDate: Wed Jul 8 20:35:57 2026 +0200 WW-4858 feat(json): enforce param-name max length on JSON population Co-Authored-By: Claude Opus 4.8 <[email protected]> --- .../java/org/apache/struts2/json/JSONInterceptor.java | 14 ++++++++++++++ .../org/apache/struts2/json/JSONInterceptorTest.java | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java index a4d084e0a..c508fee86 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java @@ -83,6 +83,7 @@ public class JSONInterceptor extends AbstractInterceptor { private int maxLength = 2_097_152; // 2MB private int maxStringLength = JSONReader.DEFAULT_MAX_STRING_LENGTH; private int maxKeyLength = JSONReader.DEFAULT_MAX_KEY_LENGTH; + private int paramNameMaxLength = 100; @SuppressWarnings("unchecked") public String intercept(ActionInvocation invocation) throws Exception { @@ -258,6 +259,10 @@ public class JSONInterceptor extends AbstractInterceptor { @SuppressWarnings("rawtypes") private boolean isAcceptableKey(String fullPath, Object target, Object action) { + if (fullPath.length() > paramNameMaxLength) { + LOG.warn("JSON body parameter [{}] is too long, allowed length is [{}]; rejected", fullPath, paramNameMaxLength); + return false; + } if (excludedPatterns != null && excludedPatterns.isExcluded(fullPath).isExcluded()) { LOG.warn("JSON body parameter [{}] matches an excluded pattern; rejected", fullPath); return false; @@ -674,6 +679,15 @@ public class JSONInterceptor extends AbstractInterceptor { this.acceptedPatterns = acceptedPatterns; } + /** + * If the dotted JSON key path exceeds the configured maximum length it will not be accepted. + * + * @param paramNameMaxLength maximum length of a JSON key path + */ + public void setParamNameMaxLength(int paramNameMaxLength) { + this.paramNameMaxLength = paramNameMaxLength; + } + @Inject(value = JSONConstants.JSON_MAX_ELEMENTS, required = false) public void setMaxElements(String maxElements) { this.maxElements = Integer.parseInt(maxElements); diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java index 2986e557f..82a562f00 100644 --- a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java +++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java @@ -749,6 +749,22 @@ public class JSONInterceptorTest extends StrutsTestCase { assertNull(action.getBar()); } + public void testParamNameMaxLengthRejectsLongKey() throws Exception { + this.request.setContent("{\"foo\":\"a\"}".getBytes()); + this.request.addHeader("Content-Type", "application/json"); + + JSONInterceptor interceptor = createInterceptor(); + interceptor.setParamNameMaxLength(2); // "foo" is length 3, over the limit + TestAction action = new TestAction(); + + this.invocation.setAction(action); + this.invocation.getStack().push(action); + + interceptor.intercept(this.invocation); + + assertNull(action.getFoo()); + } + @Override protected void setUp() throws Exception { super.setUp();
