Mark,
On 3/3/26 10:00 AM, Christopher Schultz wrote:
Mark,
On 2/25/26 4:23 AM, Mark Thomas wrote:
25 Feb 2026 07:32:00 Dimitris Soumis <[email protected]>:
On Thu, Feb 19, 2026 at 5:56 PM Christopher Schultz <
[email protected]> wrote:
All,
I recently made a change to the CSRF prevention filter in
98187ffef4cec6043a602b500a2e3dfd5ef71c20 that removed duplicate csrf
tokens in URLs in case they were being repeatedly run through
HttpServletResponse.encode().
It's possible there is a bug hiding in there but I'd like some
feedback.
I'm using Velocity Tools to generate URLs and there is a tool class
called LinkTool. It generates links with a builder-style interface with
a base URL, parameters, and so on.
After upgrading to 9.0.115, I'm finding that a very small number of
these links are being broken due to an interaction between LinkTool, my
code, and the CsrfPreventionFilter's massaging of the URLs its
producing.
The LinkTool is configured to produce HTML5-style URLs where the &
characters are encoded as &. I did triple-check to confirm that
this
was both expected and a reasonable reading of the HTML standard, which
it appears to be. That is, use of & is actually recommended in HTML
pages. RFC 6068 and WHATWG agree on this point whi, frankly, is amazing
enough that I'll go ahead and call it a Law.
Anyway, it looks like the original URL is being produced something like
this:
/context/path?csrf=C076D4BC8A49A67BE4EE7517C3A0129D
So far so good. Note that the URL has already gone through
response.encodeURL() because it's got a csrf parameter in it.
Then another parameter is added by parsing the URL above (because
#reasons, this is where my code comes in) and the URL then becomes:
/context/path?amp;id=4&csrf=C076D4BC8A49A67BE4EE7517C3A0129D
I haven't traced through the code, but I believe what's happening is
this:
1. My code, through LinkTool, adds the "id" = "4" parameter
2. LinkTool re-generates the URL String including an & parameter
separator
3. LinkTool runs the result through response.encodeURL
4. CsrfPreventionFilter removes any existing CSRF query parameters; it
finds one at the beginning of the URL and removes everything up to the
next & character
5. CsrfPreventionFilter adds its csrf token to the end of the URL
The URL is now rendered and it's broken. :/
I think plausible arguments could be made that this is a bug in any of
these 3 products: mine, VelocityTools, or Tomcat.
I'm primarily interested in getting this fixed in *my* product, but I
wonder how many other products it might effect for similar reasons.
So, the topic here is only Tomcat-related: do we think that the
CsrfPreventionFilter should consider & to be a request parameter
separator for the purposes of removing its own duplicates?
My reading of a few specs suggests that looking for "&" should be
safe since ; is a reserved character and ought to be escaped if the
user
actually intends for there to be an honest-to-goodness semicolon in
their request parameter name or value. Thus, & must mean that a
literal & was intended.
So I think it's safe (and proper) for Tomcat to consume "&" and not
just "&" in this case.
Opinions?
-chris
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
I agree, Tomcat should be fixed to consume "&", since it currently
breaks valid urls.
Kind regards,
Dimitris
I disagree.
Something LinkTool ? is confusing HTML encoding and URL encoding.
A literal & is encoded as & in HTML (and XML).
A literal & is encoded as %26 if it needs to be encoded in a URI.
I think you need to get to the bottom of why a URI is being encoded
using HTML encoding and fix that. Once that has been addressed then
you can look at the URI and see if any further work is required.
Yes, I'm using LinkTool. I honestly think the problem is probably there.
LinkTool uses a fluent API (ugh) and any time you convert the object to
a String, it will use & because it's intended to be used for
generating links in HTML.
We have a use case where we need to create a LinkTool object and re-use
it for a lot of links based upon a single root link (this use case is a
pager, where the only thing that changes is a parameter or two).
I think the issue is when we parse a URL string, it's not reversing its
own process of & -> &.
So either LinkTool needs to change, or I need to massage the strings
passed-into it for that purpose.
This is not the issue.
The problem is that LinkTool's toString implementation looks like this:
public String toString() {
String str = super.toString();
return str.length() == 0 ? str : this.response.encodeURL(str);
}
The super.toString() call is what generates the entire URL from all the
other components. It's sensitive to its "xhtml" configuration flag and,
when that's set to "true", it will generate parameter delimiters as
"&" instead of "&".
I believe there are only a few options here:
1. Stop using XHTML=true in Velocity Tools
2. Change Tomcat to allow the use of &-separated parameters
3. Modify LinkTool to stop calling response.encodeURL
I believe that Velocity Tools's implementation of XHTML-formatted URLs
is simply incompatible with Tomcat's implementation of CSRF parameter
handling.
This doesn't happen elsewhere in Tomcat because jsessionid is the only
other similar operation we perform, and the ; doesn't need any special
handling in XHTML.
I'd like to reconsider whether & should be supported, here. It's not
absolutely clear what SHOULD be done, here, but I'd like to continue the
conversation a little to see what we can come up with.
If & is NOT supported, here, then applications wanting to generate
&-separated URLs will have to:
1. Generate a URL
2. Run it through response.encodeURL
3. Post-process one more time to swap & -> &
To remove LinkTool from the conversation we could compare to how this
would need to be done using JSTL:
<c:url var="myUrl" value="/products">
<c:param name="id" value="123" />
<c:param name="category" value="books & electronics" />
</c:url>
<a href="${myUrl}">View Product</a>
To get XHTML semantics, the application would need to change the final
line to this:
<a href="<c:out value='${myUrl}' />">View Product</a>
That's fine for a single page, but doing it for the entire application
isn't practical. The application can use .jspx and I think it will use
& but that happens in the XML serializer at the very end of the
whole process.
I think Velocity Tools has just decided to handle that conversion
because there is no JSPX-style post-conversion process available to it.
I could somewhat easily be convinced that "generating URLs in a page
with & delimiters is an experiment that failed, and we should forget
that it ever happened."
-chris
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]