[
https://issues.apache.org/jira/browse/WW-5624?focusedWorklogId=1014147&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1014147
]
ASF GitHub Bot logged work on WW-5624:
--------------------------------------
Author: ASF GitHub Bot
Created on: 09/Apr/26 02:04
Start Date: 09/Apr/26 02:04
Worklog Time Spent: 10m
Work Description: tranquac opened a new pull request, #1657:
URL: https://github.com/apache/struts/pull/1657
## Summary
Fixes mass assignment bypass where JSON body (`JSONInterceptor`) and REST
body (`ContentTypeInterceptor`) deserialization bypassed `@StrutsParameter`
annotation checks, even when `struts.parameters.requireAnnotations=true`.
This patch:
- Extracts shared `ParameterAuthorizer` service from `ParametersInterceptor`
(no code duplication)
- Wires it into json-plugin and rest-plugin
- **JSON plugin**: Filters unauthorized Map keys before `populateObject()`
- **REST plugin**: Two-phase deserialization when `requireAnnotations=true`;
direct deserialization for backward compat when disabled
- OGNL `ThreadAllowlist` side effects remain in `ParametersInterceptor` only
- Full 3-level DI wiring
## Design Decisions
1. **Shared service**: Authorization logic extracted once into
`DefaultParameterAuthorizer` and shared by all interceptors.
2. **No OGNL side effects**: `ThreadAllowlist` operations stay in
`ParametersInterceptor`. JSON/REST plugins use reflection/Jackson, not OGNL.
3. **REST gated on requireAnnotations**: When disabled (default), direct
`handler.toObject()` for backward compat. When enabled, two-phase
deserialization.
4. **JSON top-level filter**: Matches `@StrutsParameter(depth=N)` model
since `JSONPopulator` uses reflection for nesting.
5. **RPC/SMD not filtered**: Different trust model (method invocation, not
property injection).
## Files Changed (13 files, +810/-10)
- `ParameterAuthorizer.java` (NEW interface)
- `DefaultParameterAuthorizer.java` (NEW impl)
- `ParametersInterceptor.java` (delegates to authorizer)
- `StrutsConstants.java`, `StrutsBeanSelectionProvider.java`,
`DefaultConfiguration.java`, `struts-beans.xml` (DI wiring)
- `JSONInterceptor.java` (inject + filter)
- `ContentTypeInterceptor.java` (inject + two-phase)
- 4 test files (19 new tests)
## Test Plan
- [x] ParameterAuthorizerTest: 15 tests
- [x] StrutsParameterAnnotationTest: 32 regression tests
- [x] ParametersInterceptorTest: 35 tests
- [x] JSONInterceptorTest: 24 tests (2 new)
- [x] ContentTypeInterceptorTest: 5 tests (2 new)
- [x] Full suites: json-plugin 122, rest-plugin 76 - zero regressions
Issue Time Tracking
-------------------
Worklog Id: (was: 1014147)
Time Spent: 50m (was: 40m)
> Request body population bypasses @StrutsParameter contract outside
> ParametersInterceptor
> ----------------------------------------------------------------------------------------
>
> Key: WW-5624
> URL: https://issues.apache.org/jira/browse/WW-5624
> Project: Struts 2
> Issue Type: Bug
> Components: Plugin - JSON, Plugin - REST
> Affects Versions: 7.1.1
> Reporter: Tran Quac
> Priority: Major
> Fix For: 7.2.0
>
> Time Spent: 50m
> Remaining Estimate: 0h
>
> h2. Summary
> {{@StrutsParameter}} enforcement is currently implemented in
> {{ParametersInterceptor}} for standard request parameter binding, but
> request-body based binders in some plugins bypass that authorization model
> and populate action/model objects directly.
> This creates inconsistent behavior between URL/form parameters and JSON/XML
> request bodies, and may allow mass assignment of properties that would
> normally be rejected by {{ParametersInterceptor}}.
> h2. Affected areas currently identified
> * JSON plugin:
> {{JSONPopulator.populateObject()}} sets properties via direct reflection and
> does not follow the full {{@StrutsParameter}} authorization rules.
> * REST plugin:
> {{JacksonJsonHandler.toObject()}} updates target objects directly via Jackson
> and does not follow the full {{@StrutsParameter}} authorization rules.
> h2. Problem scope
> The issue is broader than checking whether a setter is annotated. The current
> core contract in {{ParametersInterceptor}} also includes:
> * permitted nesting depth
> * authorization based on the exposed root member
> * ModelDriven handling
> * transition mode semantics
> * related allowlisting behavior
> Any request-body binding implementation should align with that same contract,
> otherwise Struts applies different security rules depending on how input
> reaches the action/model.
> h2. Expected direction
> Instead of implementing separate partial checks in each plugin, Struts should
> reuse or extract the shared parameter-binding authorization logic from
> {{ParametersInterceptor}} and apply it consistently across request-body
> binders.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)