An application attempted to obtain a request dispatcher with an illegal path

Hello,

a few months ago I upgraded our old XWiki instance (8.x) to XWiki 16.10.3. I ironed out some issues, but now I’ve stumbled on another issue. I found several pages that do not work anymore. First I noticed Tomcat complaining about encoded slash, so I added -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true and
-Dorg.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH=true to the CATALINA_OPT env in tomcat.conf.

However, now I get the following error for these pages (edited/redacted the URL):

08-Apr-2025 12:44:08.474 WARNING [http-nio-8080-exec-13] org.apache.catalina.core.ApplicationContext.getRequestDispatcher An application attempted to obtain a request dispatcher with an illegal path [/bin/view/%2F%2Fxwiki/intern/domain/com%2Fwiki%2Fsubwiki%2Fview%2FPage%2520One%2F/] that was rejected because it contained an encoded directory traversal attempt
        java.lang.IllegalArgumentException
                at org.apache.catalina.core.ApplicationContext.getRequestDispatcher(ApplicationContext.java:431)
                at org.apache.catalina.core.ApplicationContextFacade.getRequestDispatcher(ApplicationContextFacade.java:215)
                at org.apache.catalina.connector.Request.getRequestDispatcher(Request.java:1383)
                at org.apache.catalina.connector.RequestFacade.getRequestDispatcher(RequestFacade.java:462)
                at javax.servlet.ServletRequestWrapper.getRequestDispatcher(ServletRequestWrapper.java:278)
                at javax.servlet.ServletRequestWrapper.getRequestDispatcher(ServletRequestWrapper.java:278)
                at javax.servlet.ServletRequestWrapper.getRequestDispatcher(ServletRequestWrapper.java:278)
                at com.xpn.xwiki.web.XWikiAction.redirectSpaceURLs(XWikiAction.java:1170)
                at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:508)
                at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:338)
                at com.xpn.xwiki.web.LegacyActionServlet.service(LegacyActionServlet.java:108)
                at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:210)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at com.xpn.xwiki.web.ActionFilter.doFilter(ActionFilter.java:122)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.wysiwyg.filter.ConversionFilter.doFilter(ConversionFilter.java:61)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.container.servlet.filters.internal.SetHTTPHeaderFilter.doFilter(SetHTTPHeaderFilter.java:63)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.resource.servlet.RoutingFilter.doFilter(RoutingFilter.java:132)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.container.servlet.filters.internal.SavedRequestRestorerFilter.doFilter(SavedRequestRestorerFilter.java:208)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.container.servlet.filters.internal.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:117)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168)
                at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
                at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)
                at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
                at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
                at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:670)
                at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
                at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:346)
                at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
                at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
                at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:928)
                at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1786)
                at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
                at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
                at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
                at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
                at java.base/java.lang.Thread.run(Thread.java:840)
08-Apr-2025 12:44:08.474 SEVERE [http-nio-8080-exec-13] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [action] in context with path [] threw exception [Failed to execute the action with name [view]] with root cause
        java.lang.NullPointerException: Cannot invoke "javax.servlet.RequestDispatcher.forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)" because the return value of "com.xpn.xwiki.web.XWikiRequest.getRequestDispatcher(String)" is null
                at com.xpn.xwiki.web.XWikiAction.redirectSpaceURLs(XWikiAction.java:1170)
                at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:508)
                at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:338)
                at com.xpn.xwiki.web.LegacyActionServlet.service(LegacyActionServlet.java:108)
                at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:210)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at com.xpn.xwiki.web.ActionFilter.doFilter(ActionFilter.java:122)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.wysiwyg.filter.ConversionFilter.doFilter(ConversionFilter.java:61)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.container.servlet.filters.internal.SetHTTPHeaderFilter.doFilter(SetHTTPHeaderFilter.java:63)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.resource.servlet.RoutingFilter.doFilter(RoutingFilter.java:132)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.container.servlet.filters.internal.SavedRequestRestorerFilter.doFilter(SavedRequestRestorerFilter.java:208)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.xwiki.container.servlet.filters.internal.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:117)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:179)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:154)
                at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168)
                at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
                at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)
                at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
                at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
                at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:670)
                at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
                at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:346)
                at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
                at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
                at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:928)
                at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1786)
                at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
                at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
                at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
                at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
                at java.base/java.lang.Thread.run(Thread.java:840)

I’m not sure why these subpages are affected, as some others with no discernable differences on the same page level are fine. For example:

https://xwiki.intern.domain.com/wiki/subwiki/view/Page%20One/ChildOne/ - doesn’t work
https://xwiki.intern.domain.com/wiki/subwiki/view/Page%20One/Child%20Two/ - works
https://xwiki.intern.domain.com/wiki/subwiki/view/Page%20One/Child-Three/ - doesn’t work
https://xwiki.intern.domain.com/wiki/subwiki/view/Page%20One/Child%20Four/ - doesn’t work
https://xwiki.intern.domain.com/wiki/subwiki/view/Page%20One/Child%20Five/Grandchild%20One%20Yellow/ - works
https://xwiki.intern.domain.com/wiki/subwiki/view/Page%20One/Child%20Five/Grandchild%20Two%20Green/ - doesn’t work
https://xwiki.intern.domain.com/wiki/subwiki/view/Page%20One/Child%20Five/Grandchild%20Three%20Blue%207.0/ - doesn’t work

Obviously there’s something going on with the path encoding, but I don’t understand what.

XWiki: 16.10.3
Tomcat: 9.0.87
Nginx: 1.20.1 (tests performed locally without it)
DB: Postgres 16.6
OS: RHEL 9.5

Bump. Anyone any ideas?

Bump. Still no idea how to fix this or where to look. Bottom line is the subwiki URL for some sub-pages gets incorrectly parsed/decoded and redirected to the main wiki, e.g.:
https://xwiki.intern.domain.com/wiki/subwiki/view/Page%20One/Sub-Page/
gets redirected to
https://xwiki.intern.domain.com/bin/view/%2F%2Fxwiki/intern/domain/com%2Fwiki%2Fsubwiki%2Fview%2FPage%2520One%2F

This also happens when testing locally without the proxy and https.

Further investigation, I think I figured out part of it.

I looked up all the offending pages through the search option and all of them were last edited on the same day by XWikiGuest. They’re also only visible to the Administrator account (i.e. account with admin rights) in the site tree and search. I located and managed to access a subpage of one of the affected pages. For that subpage XWiki returns a list of deleted pages with that title with a single entry. The page is reported to have been deleted on the same day on which XWiki search reports all the affected pages were last edited. That clued me in that this user actually deleted all these pages, but for some reason, XWiki didn’t handle it properly, and instead I’m getting weird redirects to the main Wiki and XWikiGuest being listed as the last editor (which is otherwise impossible, because the entire Wiki is locked down with LDAP).

With that said, the problem here is actually something else entirely. These pages shouldn’t exist anymore, but instead of returning a normal XWiki page with a list of entries in the recyle bin or offering an option to create a new page with that title, XWiki performs a redirect by adding the URL of the affected page to the URL of the main Wiki. The question is why?