Tomcat Cookies rejected with $prefix - i.e. Twilio webhooks

OS: Windows Server 2019 (10.0) 64bit
Java Version: 21.0.7 (Eclipse Adoptium) 64bit
Tomcat Version: Apache Tomcat/11.0.6
Lucee Version: 6.2.1.112-RC

Using Twilio webhooks to log incoming text messages. It appears they are sending a $Version cookie which Tomcat is throwing an error - java.lang.IllegalArgumentException: Cookie name “$Version” is a reserved token javax.servlet.http.Cookie. Is there anyway to set Tomcat to be less strict on this? I was trying to get IIS to do a reverse proxy to localhost using URL redirect and stripping the cookies but that isn’t working either.

Any help is appreciated.

what’s the full stacktrace?

22-Jul-2025 09:41:24.185 SEVERE [ajp-nio-127.0.0.1-8009-exec-4] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [CFMLServlet] in context with path threw exception
java.lang.IllegalArgumentException: Cookie name “$Version” is a reserved token
at javax.servlet.http.Cookie.(Cookie.java:151)
at lucee.loader.servlet.jakarta.HttpServletRequestJavax.getCookies(HttpServletRequestJavax.java:38)
at lucee.runtime.net.http.HTTPServletRequestWrap.getCookies(HTTPServletRequestWrap.java:539)
at lucee.runtime.net.http.ReqRspUtil.getCookies(ReqRspUtil.java:144)
at lucee.runtime.type.scope.CookieImpl.initialize(CookieImpl.java:359)
at lucee.runtime.PageContextImpl.cookieScope(PageContextImpl.java:1771)
at lucee.runtime.type.scope.UndefinedImpl.reinitialize(UndefinedImpl.java:651)
at lucee.runtime.type.scope.UndefinedImpl.initialize(UndefinedImpl.java:630)
at lucee.runtime.type.scope.UndefinedImpl.initialize(UndefinedImpl.java:600)
at lucee.runtime.PageContextImpl.initialize(PageContextImpl.java:576)
at lucee.runtime.CFMLFactoryImpl.getPageContextImpl(CFMLFactoryImpl.java:248)
at lucee.runtime.engine.CFMLEngineImpl._service(CFMLEngineImpl.java:1077)
at lucee.runtime.engine.CFMLEngineImpl.serviceCFML(CFMLEngineImpl.java:1066)
at lucee.loader.engine.CFMLEngineWrapper.serviceCFML(CFMLEngineWrapper.java:97)
at lucee.loader.servlet.jakarta.CFMLServlet.service(CFMLServlet.java:52)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:130)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:109)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:79)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:116)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:420)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:903)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:59)
at java.base/java.lang.Thread.run(Unknown Source)

Tomcat strictly follows the RFC, you might be able to rewrite the cookies in IIS before it reaches tomcat?

I’m not having much luck with the redirect. I was hoping there would be a setting within Tomcat to relax RFC.

Doesn’t seem Tomcat allows that.

you could try something like

https://www.perplexity.ai/search/how-to-rename-cookies-using-re-Qr3WXhEUQDW.YDE1LoUP_A

1 Like

That fixed my problem. My solution:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="RenameDollarVersionCookie" stopProcessing="true">
          <match url=".*" />
          <conditions>
            <add input="{HTTP_COOKIE}" pattern="(^|; )\$Version=([^;]*)" />
          </conditions>
          <serverVariables>
            <set name="HTTP_COOKIE" value="{C:1}_Version={C:2}" />
          </serverVariables>
          <action type="None" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>
2 Likes

@Mike_Hall Awesome post!!! Thank your for sharing, really nice having it documented here!

1 Like

I ended up here after researching the same error (Vonage/Nexmo instead of Twilio). As I’m on ubuntu I thought I’d update here how I resolved this for future googlers :slight_smile:

I tried implementing a fix first inside server.xml by adding rejectIllegalHeader=“false” to the connector after some online research. That didn’t work. Tried a fix in application.cfc which I figured didn’t have much chance of working, and it didn’t. Ultimately decided it must already be failing when apache sent it onwards, so added the following to the virtual host in question (where /xyz/ is the folder dealing with different webhooks):

<Location /xyz/>
	RequestHeader unset Cookie
    	RequestHeader set Cookie "%{Cookie}e"
</Location>