Summary
WebUtils.getPathWithinApplication() returns null when the request path normalizes above root. This null propagates through PathMatchingFilterChainResolver.getChain() which cannot match any pattern (including /**), and AbstractShiroFilter.getExecutionChain() falls back to the original container FilterChain — bypassing all Shiro security filters.
Note: This is hardening only. Currently there is no servlet container which would allow such a path into Shiro
Root Cause
Commit b90f918 (Shiro 1.5.3, CVE-2020-11989 fix) changed getPathWithinApplication() to:
return normalize(removeSemicolon(getServletPath(request) + getPathInfo(request)));
normalize() returns null when the path contains /../ at index 0 (trying to go above root). Unlike the old implementation (which always returned a valid path), this null is never handled downstream.
Resolution
PR #2836 fixes this by failing closed: getPathWithinApplication() throws IllegalStateException when normalize() returns null or an empty path, so the request is rejected instead of being served through the unfiltered container chain. Throwing — rather than remapping the path to / — also avoids selecting a dedicated (often more permissive) / chain when a traversal request is normalized to the application root.
Summary
WebUtils.getPathWithinApplication()returnsnullwhen the request path normalizes above root. Thisnullpropagates throughPathMatchingFilterChainResolver.getChain()which cannot match any pattern (including/**), andAbstractShiroFilter.getExecutionChain()falls back to the original containerFilterChain— bypassing all Shiro security filters.Note: This is hardening only. Currently there is no servlet container which would allow such a path into Shiro
Root Cause
Commit b90f918 (Shiro 1.5.3, CVE-2020-11989 fix) changed
getPathWithinApplication()to:normalize()returnsnullwhen the path contains/../at index 0 (trying to go above root). Unlike the old implementation (which always returned a valid path), this null is never handled downstream.Resolution
PR #2836 fixes this by failing closed:
getPathWithinApplication()throwsIllegalStateExceptionwhennormalize()returnsnullor an empty path, so the request is rejected instead of being served through the unfiltered container chain. Throwing — rather than remapping the path to/— also avoids selecting a dedicated (often more permissive)/chain when a traversal request is normalized to the application root.