[
https://issues.apache.org/jira/browse/WW-5839?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Gouri Sankar A updated WW-5839:
-------------------------------
Description:
AbstractMatcher/ActionConfigMatcher: a wildcard "\{n}" substituted into an
action/result/exception-mapping class= attribute was unconfined -- any matched
path segment, including one containing "." or "/", landed verbatim in the
resulting class name. The sibling method-name slot is already gated
(ActionConfig#isAllowedMethod); there was no equivalent gate for the class-name
slot.
Fix rejects a substituted value outside [A-Za-z0-9_$]* when filling a
class-name slot, instead of using it verbatim.
Reachable only if a developer writes a wildcard mapping that substitutes into
class= -- application-responsibility, not a default-config issue.
Tests: WildcardClassNameHardeningTest (new, 2 tests). Full core suite: 3742/0
failures.
Affected versions: present, same code pattern, by source inspection, in the
6.12.0, 7.0.0, 7.3.0 and 7.4.0 tags.
Pull request: https://github.com/apache/struts/pull/2115 (already open,
narrowed)
was:
Three small, independent hardening items found in the same review pass. None is
a documented Struts control that fails to hold (SECURITY.md's "no control
claimed" case), so filing as public hardening rather than privately.
1) AbstractMatcher/ActionConfigMatcher (core): a wildcard "\{n}" substituted
into an action/result/exception-mapping class= attribute was unconfined -- any
matched path segment, including one containing "." or "/", landed verbatim in
the resulting class name. The sibling method-name slot is already gated
(ActionConfig#isAllowedMethod); there was no equivalent gate for the class-name
slot. Fix rejects a substituted value outside [A-Za-z0-9_$]* when filling a
class-name slot, instead of using it verbatim. Reachable only if a developer
writes a wildcard mapping that substitutes into class= --
application-responsibility, not a default-config issue.
2) UploadedFile/ActionFileUploadInterceptor (core): the client-supplied
original file name was handed to actions unsanitised via getOriginalName(), a
regression from the pre-7.0 MultiPartRequest#getFileNames()/getCanonicalName()
path-stripping pair, which has no caller in the current action-based upload
flow. Struts itself never builds a filesystem path from the raw name (the
on-disk temp file is UUID-named via getName()); this only matters if
application code does. Fix adds a default method
UploadedFile#getSanitizedOriginalName() (basename only, via
FilenameUtils.getName) alongside the existing raw accessor, with javadoc on
both making the raw/sanitised distinction explicit.
3) StrutsBootServer (boot, 7.5.0, unreleased -- no production deployments yet):
without a web.xml, the embedded Tomcat context defaulted to the servlet-spec
COOKIE+URL session tracking modes, so a session id supplied only via
";jsessionid=" in the URL (no cookie at all) was accepted and kept alive with
no fresh Set-Cookie -- a session-fixation vector. Live-reproduced on a
throwaway Boot app before the fix: a session established by cookie was resumed
by replaying the id via the URL parameter with no Cookie header sent at all.
Fix restricts session tracking to COOKIE only, and the session cookie now
carries SameSite=Lax (previously unset). Secure is deliberately not forced:
Boot opens a plain HTTP listener by default, and an operator terminating TLS in
front of it sets Secure themselves, as with any other servlet container.
Tests: WildcardClassNameHardeningTest (new, 2 tests);
AbstractMultiPartRequestTest gains a benign-marker test proving the raw
accessor is unsanitised and the new sanitised one is not; StrutsBootTomcatTest
gains testSessionCookieHasSameSiteLax and a
URL-supplied-session-id-is-not-honoured test, with a
cookie-based-session-still-works control. Full core suite: 3629 run, 0
failures, 2 skipped. Full boot suite: 52 run, 0 failures. Existing
ActionConfigMatcherTest (9), AbstractMatcherTest (1),
JakartaMultiPartRequestTest (42) and JakartaStreamMultiPartRequestTest (43) all
pass unaffected.
Affected versions: items 1 and 2 verified present (same code pattern, by source
inspection) in the 6.12.0, 7.0.0, 7.3.0 and 7.4.0 tags. Item 3 is boot/, new in
7.5.0 (unreleased), so no released version is affected by it.
> Reject unconfined wildcard substitution into class= attributes
> --------------------------------------------------------------
>
> Key: WW-5839
> URL: https://issues.apache.org/jira/browse/WW-5839
> Project: Struts 2
> Issue Type: Improvement
> Components: Core
> Affects Versions: 6.12.0, 7.0.0, 7.3.0, 7.4.0
> Reporter: Gouri Sankar A
> Priority: Minor
> Fix For: 7.5.0
>
> Time Spent: 0.5h
> Remaining Estimate: 0h
>
> AbstractMatcher/ActionConfigMatcher: a wildcard "\{n}" substituted into an
> action/result/exception-mapping class= attribute was unconfined -- any
> matched path segment, including one containing "." or "/", landed verbatim in
> the resulting class name. The sibling method-name slot is already gated
> (ActionConfig#isAllowedMethod); there was no equivalent gate for the
> class-name slot.
> Fix rejects a substituted value outside [A-Za-z0-9_$]* when filling a
> class-name slot, instead of using it verbatim.
> Reachable only if a developer writes a wildcard mapping that substitutes into
> class= -- application-responsibility, not a default-config issue.
> Tests: WildcardClassNameHardeningTest (new, 2 tests). Full core suite: 3742/0
> failures.
> Affected versions: present, same code pattern, by source inspection, in the
> 6.12.0, 7.0.0, 7.3.0 and 7.4.0 tags.
> Pull request: https://github.com/apache/struts/pull/2115 (already open,
> narrowed)
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)