This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
     new 8660a6e1a9 Ensure URL encoding issues trigger errors.
8660a6e1a9 is described below

commit 8660a6e1a92606779854d9b329e48f5e46f273de
Author: Mark Thomas <[email protected]>
AuthorDate: Mon Jan 19 10:08:32 2026 +0000

    Ensure URL encoding issues trigger errors.
    
    Should be a NO-OP unless someone has a Rewrite valve configuration that
    is inconsistent with the Connector's URI encoding - in which case the
    new IAE will highlight this.
    
    Originated from a report from OSS-Fuzz that found some cases where a
    round-trip encode/decode have the same result as the input.
---
 java/org/apache/catalina/util/URLEncoder.java     | 14 +++++++++---
 test/org/apache/catalina/util/TestURLEncoder.java | 28 +++++++++++++++++++++++
 webapps/docs/changelog.xml                        |  4 ++++
 3 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/catalina/util/URLEncoder.java 
b/java/org/apache/catalina/util/URLEncoder.java
index 0e0f9737d9..1f031058f1 100644
--- a/java/org/apache/catalina/util/URLEncoder.java
+++ b/java/org/apache/catalina/util/URLEncoder.java
@@ -20,6 +20,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.nio.charset.Charset;
+import java.nio.charset.CodingErrorAction;
 import java.util.BitSet;
 
 /**
@@ -146,7 +147,15 @@ public final class URLEncoder implements Cloneable {
         int maxBytesPerChar = 10;
         StringBuilder rewrittenPath = new StringBuilder(path.length());
         ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
-        OutputStreamWriter writer = new OutputStreamWriter(buf, charset);
+        /*
+         * Most calls to this method use UTF-8 where malformed input and 
unmappable character issues are not expected to
+         * happen. The only Tomcat code that currently (January 2026) might 
call this method with something other than
+         * UTF-8 is the rewrite valve. In that case, the rewrite rules should 
be consistent with the configured URI
+         * encoding on the Connector. Given all of this, the IAE is only 
expected to be thrown as a result of
+         * configuration errors.
+         */
+        OutputStreamWriter writer = new OutputStreamWriter(buf, 
charset.newEncoder()
+                
.onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT));
 
         for (int i = 0; i < path.length(); i++) {
             int c = path.charAt(i);
@@ -160,8 +169,7 @@ public final class URLEncoder implements Cloneable {
                     writer.write((char) c);
                     writer.flush();
                 } catch (IOException ioe) {
-                    buf.reset();
-                    continue;
+                    throw new IllegalArgumentException(ioe);
                 }
                 byte[] ba = buf.toByteArray();
                 for (byte toEncode : ba) {
diff --git a/test/org/apache/catalina/util/TestURLEncoder.java 
b/test/org/apache/catalina/util/TestURLEncoder.java
index dbef0fb60e..47fc3ede15 100644
--- a/test/org/apache/catalina/util/TestURLEncoder.java
+++ b/test/org/apache/catalina/util/TestURLEncoder.java
@@ -16,11 +16,14 @@
  */
 package org.apache.catalina.util;
 
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 
 import org.junit.Assert;
 import org.junit.Test;
 
+import org.apache.tomcat.util.buf.UDecoder;
+
 public class TestURLEncoder {
 
     private static final String SPACE = " ";
@@ -53,4 +56,29 @@ public class TestURLEncoder {
         xml.removeSafeCharacter('&');
         Assert.assertEquals(AMPERSAND_ENCODED, xml.encode(AMPERSAND, 
StandardCharsets.UTF_8));
     }
+
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testOssFuzz01() {
+        /*
+         * Round-trip URL encoding with ASCII only works for valid ASCII 
characters.
+         */
+        testRoundTrip("\uFFFD", StandardCharsets.US_ASCII);
+    }
+
+
+    @Test
+    public void testOssFuzz02() {
+        testRoundTrip("\uFFFD", StandardCharsets.UTF_8);
+    }
+
+
+    private void testRoundTrip(String input, Charset charset) {
+        URLEncoder encoder = new URLEncoder();
+
+        String encoded = encoder.encode(input, charset);
+        String decoded = UDecoder.URLDecode(encoded, charset);
+
+        Assert.assertEquals(input, decoded);
+    }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 6373485000..6e6a645031 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -216,6 +216,10 @@
         Authenticators that provides a per Authenticator override of the SSO
         Valve <code>requireReauthentication</code> attribute. (markt)
       </add>
+      <fix>
+        Ensure URL encoding errors in the Rewrite Valve trigger an exception
+        rather than silently using a replacement character. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to