From 4a3fbbcdb65cf3df2bcf1f5750029aef5b2f7333 Mon Sep 17 00:00:00 2001 From: pkgagent Date: Thu, 24 Sep 2026 02:00:05 +0800 Subject: [PATCH] Fix CVE-2026-76183: WebSocket endpoint security constraint bypass via URI template matching --- tomcat-9.0.121-CVE-2026-76183.patch | 193 ++++++++++++++++++++++++++++ tomcat.spec | 8 +- 2 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 tomcat-9.0.121-CVE-2026-76183.patch diff --git a/tomcat-9.0.121-CVE-2026-76183.patch b/tomcat-9.0.121-CVE-2026-76183.patch new file mode 100644 index 0000000..0fc9149 --- /dev/null +++ b/tomcat-9.0.121-CVE-2026-76183.patch @@ -0,0 +1,193 @@ +From a93a60a33f4cc202542eb6a0b87b7142d7db311c Mon Sep 17 00:00:00 2001 +From: Mark Thomas +Date: Wed, 19 Aug 2026 11:32:22 +0100 +Subject: [PATCH] Allow WebSocket request URIs to contain '{' and/or '}' + +--- + .../websocket/server/LocalStrings.properties | 1 + + .../tomcat/websocket/server/UriTemplate.java | 35 +++++++--- + .../websocket/server/WsServerContainer.java | 2 +- + .../websocket/server/TestUriTemplate.java | 68 +++++++++++++++++++ + webapps/docs/changelog.xml | 5 ++ + 5 files changed, 99 insertions(+), 12 deletions(-) + +diff --git java/org/apache/tomcat/websocket/server/LocalStrings.properties java/org/apache/tomcat/websocket/server/LocalStrings.properties +index 6bcedbe..08e0c60 100644 +--- java/org/apache/tomcat/websocket/server/LocalStrings.properties ++++ java/org/apache/tomcat/websocket/server/LocalStrings.properties +@@ -27,6 +27,7 @@ serverContainer.servletContextMissing=No ServletContext was specified + upgradeUtil.incompatibleRsv=Extensions were specified that have incompatible RSV bit usage + upgradeUtil.pojoMapFail=Unable to complete method mapping for POJO class [{0}] + ++uriTemplate.candidateParameters=Candidate URIs are not permitted to contain URI template parameters + uriTemplate.duplicateParameter=The parameter [{0}] appears more than once in the path which is not permitted + uriTemplate.invalidPath=The path [{0}] is not valid. + uriTemplate.invalidSegment=The segment [{0}] is not valid in the provided path [{1}] +diff --git java/org/apache/tomcat/websocket/server/UriTemplate.java java/org/apache/tomcat/websocket/server/UriTemplate.java +index 384b792..441ae77 100644 +--- java/org/apache/tomcat/websocket/server/UriTemplate.java ++++ java/org/apache/tomcat/websocket/server/UriTemplate.java +@@ -48,6 +48,10 @@ public class UriTemplate { + * @throws DeploymentException if the path is invalid + */ + public UriTemplate(String path) throws DeploymentException { ++ this(path, true); ++ } ++ ++ public UriTemplate(String path, boolean parseParameters) throws DeploymentException { + + if (path == null || !path.startsWith("/") || path.contains("/../") || path.contains("/./") || + path.contains("//")) { +@@ -74,19 +78,23 @@ public class UriTemplate { + } + normalized.append('/'); + int index = -1; +- if (segment.startsWith("{") && segment.endsWith("}")) { +- index = segmentCount; +- segment = segment.substring(1, segment.length() - 1); +- normalized.append('{'); +- normalized.append(paramCount++); +- normalized.append('}'); +- if (!paramNames.add(segment)) { +- throw new DeploymentException(sm.getString("uriTemplate.duplicateParameter", segment)); ++ if (parseParameters) { ++ if (segment.startsWith("{") && segment.endsWith("}")) { ++ index = segmentCount; ++ segment = segment.substring(1, segment.length() - 1); ++ normalized.append('{'); ++ normalized.append(paramCount++); ++ normalized.append('}'); ++ if (!paramNames.add(segment)) { ++ throw new DeploymentException(sm.getString("uriTemplate.duplicateParameter", segment)); ++ } ++ } else { ++ if (segment.contains("{") || segment.contains("}")) { ++ throw new DeploymentException(sm.getString("uriTemplate.invalidSegment", segment, path)); ++ } ++ normalized.append(segment); + } + } else { +- if (segment.contains("{") || segment.contains("}")) { +- throw new DeploymentException(sm.getString("uriTemplate.invalidSegment", segment, path)); +- } + normalized.append(segment); + } + this.segments.add(new Segment(index, segment)); +@@ -106,6 +114,11 @@ public class UriTemplate { + */ + public Map match(UriTemplate candidate) { + ++ // Candidate URIs should not contain parameters. ++ if (candidate.hasParameters) { ++ throw new IllegalStateException(sm.getString("uriTemplate.candidateParameters")); ++ } ++ + Map result = new HashMap<>(); + + // Should not happen but for safety +diff --git java/org/apache/tomcat/websocket/server/WsServerContainer.java java/org/apache/tomcat/websocket/server/WsServerContainer.java +index d1b2aba..c17da41 100644 +--- java/org/apache/tomcat/websocket/server/WsServerContainer.java ++++ java/org/apache/tomcat/websocket/server/WsServerContainer.java +@@ -365,7 +365,7 @@ public class WsServerContainer extends WsWebSocketContainer implements ServerCon + // No exact match. Need to look for template matches. + UriTemplate pathUriTemplate; + try { +- pathUriTemplate = new UriTemplate(path); ++ pathUriTemplate = new UriTemplate(path, false); + } catch (DeploymentException e) { + // Path is not valid so can't be matched to a WebSocketEndpoint + return null; +diff --git test/org/apache/tomcat/websocket/server/TestUriTemplate.java test/org/apache/tomcat/websocket/server/TestUriTemplate.java +index 33fffce..29f1386 100644 +--- test/org/apache/tomcat/websocket/server/TestUriTemplate.java ++++ test/org/apache/tomcat/websocket/server/TestUriTemplate.java +@@ -216,4 +216,72 @@ public class TestUriTemplate { + @SuppressWarnings("unused") + UriTemplate t = new UriTemplate("//b"); + } ++ ++ ++ @Test ++ public void testCandidateBraces01() throws Exception { ++ UriTemplate t = new UriTemplate("/a/b/{c}"); ++ Map result = t.match(new UriTemplate("/a/{b}/other", false)); ++ Assert.assertNull(result); ++ } ++ ++ ++ @Test ++ public void testCandidateBraces02() throws Exception { ++ UriTemplate t = new UriTemplate("/a/b/{c}"); ++ Map result = t.match(new UriTemplate("/a/b/{other}", false)); ++ Assert.assertNotNull(result); ++ Assert.assertEquals(1, result.size()); ++ Assert.assertEquals("{other}", result.get("c")); ++ } ++ ++ ++ @Test ++ public void testCandidateBraces03() throws Exception { ++ UriTemplate t = new UriTemplate("/a/b/{c}"); ++ Map result = t.match(new UriTemplate("/a/b/ot{h}er", false)); ++ Assert.assertNotNull(result); ++ Assert.assertEquals(1, result.size()); ++ Assert.assertEquals("ot{h}er", result.get("c")); ++ } ++ ++ ++ @Test ++ public void testCandidateBraces04() throws Exception { ++ UriTemplate t = new UriTemplate("/a/b/{c}"); ++ Map result = t.match(new UriTemplate("/a/b/{other", false)); ++ Assert.assertNotNull(result); ++ Assert.assertEquals(1, result.size()); ++ Assert.assertEquals("{other", result.get("c")); ++ } ++ ++ ++ @Test ++ public void testCandidateBraces05() throws Exception { ++ UriTemplate t = new UriTemplate("/a/b/{c}"); ++ Map result = t.match(new UriTemplate("/a/b/ot{her", false)); ++ Assert.assertNotNull(result); ++ Assert.assertEquals(1, result.size()); ++ Assert.assertEquals("ot{her", result.get("c")); ++ } ++ ++ ++ @Test ++ public void testCandidateBraces06() throws Exception { ++ UriTemplate t = new UriTemplate("/a/b/{c}"); ++ Map result = t.match(new UriTemplate("/a/b/other}", false)); ++ Assert.assertNotNull(result); ++ Assert.assertEquals(1, result.size()); ++ Assert.assertEquals("other}", result.get("c")); ++ } ++ ++ ++ @Test ++ public void testCandidateBraces07() throws Exception { ++ UriTemplate t = new UriTemplate("/a/b/{c}"); ++ Map result = t.match(new UriTemplate("/a/b/oth}er", false)); ++ Assert.assertNotNull(result); ++ Assert.assertEquals(1, result.size()); ++ Assert.assertEquals("oth}er", result.get("c")); ++ } + } +diff --git webapps/docs/changelog.xml webapps/docs/changelog.xml +index 6af09c3..8f70874 100644 +--- webapps/docs/changelog.xml ++++ webapps/docs/changelog.xml +@@ -293,6 +293,11 @@ + closure because they were created under an authenticated HTTP session + that has since ended. (markt) + ++ ++ Fix overly broad check that prevented request URIs containing literal ++ { and } characters from being mapped to ++ WebSocket end points. (markt) ++ + + + diff --git a/tomcat.spec b/tomcat.spec index 31282ee..9fdda0c 100644 --- a/tomcat.spec +++ b/tomcat.spec @@ -14,7 +14,7 @@ Summary: Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API Name: tomcat Version: 9.0.121 -Release: 1%{?dist} +Release: 2%{?dist} License: ASL 2.0 URL: http://tomcat.apache.org/ Source0: https://dlcdn.apache.org/tomcat/tomcat-%{major_version}/v%{version}/src/%{packdname}.tar.gz @@ -38,6 +38,8 @@ Patch3003: %{name}-%{major_version}.%{minor_version}-catalina-policy.patch Patch3004: rhbz-1857043.patch Patch3006: %{name}-%{major_version}.%{minor_version}-bnd-annotation.patch +Patch0001: %{name}-%{version}-CVE-2026-76183.patch + BuildRequires: ant ecj findutils java-devel javapackages-local systemd # for using mvn macro BuildRequires: javapackages-common @@ -453,6 +455,10 @@ fi %{_var}/lib/%{name}/webapps/ROOT %changelog +* Wed Sep 23 2026 PkgAgent Robot - 9.0.121-2 +- [Type] security +- [DESC] Fix CVE-2026-76183: WebSocket endpoint security constraint bypass via URI template matching + * Thu Sep 17 2026 PkgAgent Robot - 9.0.121-1 - [Type] security - [DESC] Update to 9.0.121 (fixes CVE-2026-65905, CVE-2026-65182, CVE-2026-65927, CVE-2026-66422, CVE-2026-73180, CVE-2026-65637, CVE-2026-65183) -- Gitee