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

markt-asf pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git


The following commit(s) were added to refs/heads/master by this push:
     new 8da74df8 Implement stricter checks for fields using RFC 2231 / RFC 
5987 (#470)
8da74df8 is described below

commit 8da74df856ff04486455332e8304778ea6de5ed5
Author: Mark Thomas <[email protected]>
AuthorDate: Tue May 12 08:02:33 2026 +0100

    Implement stricter checks for fields using RFC 2231 / RFC 5987 (#470)
    
    Implement stricter checks for fields using RFC 2231 / RFC 5987
    
    Invalid characters or %nn encoded values that include non-hex values in the 
extended value will cause the value to be ignored.
    Includes some changes prompted by a CoPilot review
---
 .../commons/fileupload2/core/ParameterParser.java  |  3 ++
 .../commons/fileupload2/core/RFC2231Utils.java     | 48 +++++++++++++++++++---
 .../fileupload2/core/RFC2231UtilityTestCase.java   | 18 ++++++++
 src/changes/changes.xml                            |  1 +
 4 files changed, 65 insertions(+), 5 deletions(-)

diff --git 
a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/ParameterParser.java
 
b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/ParameterParser.java
index 513b9376..0daf413a 100644
--- 
a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/ParameterParser.java
+++ 
b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/ParameterParser.java
@@ -176,6 +176,9 @@ public class ParameterParser {
                 if (paramValue != null) {
                     try {
                         paramValue = RFC2231Utils.hasEncodedValue(paramName) ? 
RFC2231Utils.decodeText(paramValue) : MimeUtils.decodeText(paramValue);
+                    } catch (final IllegalArgumentException iae) {
+                        // Treat invalid values as if they were not provided
+                        paramValue = null;
                     } catch (final UnsupportedEncodingException ignored) {
                         // let's keep the original value in this case
                     }
diff --git 
a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/RFC2231Utils.java
 
b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/RFC2231Utils.java
index 11c8c749..3e3d13d8 100644
--- 
a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/RFC2231Utils.java
+++ 
b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/RFC2231Utils.java
@@ -43,23 +43,54 @@ final class RFC2231Utils {
     private static final byte MASK = 0x7f;
 
     /**
-     * The Hexadecimal representation of 128.
+     * ASCII DEL character.
      */
-    private static final int MASK_128 = 0x80;
+    private static final int DEL = 127;
+
+    /**
+     * Number of ASCII code points.
+     */
+    private static final int ASCII_CODE_POINT_COUNT = 128;
 
     /**
      * The Hexadecimal decode value.
      */
-    private static final byte[] HEX_DECODE = new byte[MASK_128];
+    private static final byte[] HEX_DECODE = new byte[ASCII_CODE_POINT_COUNT];
+
+    /**
+     * Flags, one for each ASCII code point, that indicate if that code point 
is valid for use in an RFC 5987 extended
+     * attribute value.
+     */
+    private static final boolean[] ATTR_CHAR = new 
boolean[ASCII_CODE_POINT_COUNT];
 
     // create a ASCII decoded array of Hexadecimal values
     static {
+        // Initialise all values to invalid
+        for (var i = 0; i < ASCII_CODE_POINT_COUNT; i++) {
+            HEX_DECODE[i] = -1;
+        }
+        // Configure the valid hex digits
         for (var i = 0; i < HEX_DIGITS.length; i++) {
             HEX_DECODE[HEX_DIGITS[i]] = (byte) i;
             HEX_DECODE[Character.toLowerCase(HEX_DIGITS[i])] = (byte) i;
         }
+
+        for (var i = 0; i < ASCII_CODE_POINT_COUNT; i++) {
+            // See RFC 5987
+            if (!(i < ' ' || i == ' ' || i == '\"' || i == '%' || i == '\'' || 
i == '(' || i == ')' || i == '*' || i == ','
+                    || i == '/' || i == ':' || i == ';' || i == '<' || i == 
'=' || i == '>' || i == '?' || i == '@'
+                    || i == '[' || i == '\\' || i == ']' || i == '{' || i == 
'}' || i == DEL)) {
+                ATTR_CHAR[i] = true;
+            }
+        }
     }
 
+
+    static boolean isAttrChar(final char c) {
+        return c < ASCII_CODE_POINT_COUNT && ATTR_CHAR[c];
+    }
+
+
     /**
      * Decodes a string of text obtained from a HTTP header as per RFC 2231
      *
@@ -71,9 +102,10 @@ final class RFC2231Utils {
      *
      * @param encodedText   Text to be decoded has a format of {@code 
<charset>'<language>'<encoded_value>} and ASCII only
      * @return Decoded text based on charset encoding
+     * @throws IllegalArgumentException The encoded text contained characters 
not permitted by RFC 2231
      * @throws UnsupportedEncodingException The requested character set wasn't 
found.
      */
-    static String decodeText(final String encodedText) throws 
UnsupportedEncodingException {
+    static String decodeText(final String encodedText) throws 
IllegalArgumentException, UnsupportedEncodingException {
         final var langDelimitStart = encodedText.indexOf('\'');
         if (langDelimitStart == -1) {
             // missing charset
@@ -89,6 +121,7 @@ final class RFC2231Utils {
         return new String(bytes, getJavaCharset(mimeCharset));
     }
 
+
     /**
      * Converts {@code text} to their corresponding Hex value.
      *
@@ -106,9 +139,14 @@ final class RFC2231Utils {
                 }
                 final var b1 = HEX_DECODE[text.charAt(i++) & MASK];
                 final var b2 = HEX_DECODE[text.charAt(i++) & MASK];
+                if (b1 < 0 || b2 < 0) {
+                    throw new IllegalArgumentException();
+                }
                 out.write(b1 << shift | b2);
-            } else {
+            } else if (isAttrChar(c)) {
                 out.write((byte) c);
+            } else {
+                throw new IllegalArgumentException();
             }
         }
         return out.toByteArray();
diff --git 
a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/RFC2231UtilityTestCase.java
 
b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/RFC2231UtilityTestCase.java
index a2ec817d..bc431de0 100644
--- 
a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/RFC2231UtilityTestCase.java
+++ 
b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/RFC2231UtilityTestCase.java
@@ -82,4 +82,22 @@ public final class RFC2231UtilityTestCase {
         final var nameWithoutAsterisk = "paramname";
         assertEquals("paramname", 
RFC2231Utils.stripDelimiter(nameWithoutAsterisk));
     }
+
+
+    @Test
+    void testDecodeNonTokenCharacters() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> 
RFC2231Utils.decodeText("ISO-8859-1''Not*allowed"));
+    }
+
+
+    @Test
+    void testDecodeUTF8Characters() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> 
RFC2231Utils.decodeText("UTF-8''\\u8a2e"));
+    }
+
+
+    @Test
+    void testDecodeInvalidHex() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> 
RFC2231Utils.decodeText("ISO-8859-1''hello%HHworld"));
+    }
 }
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 68947466..e2e80e00 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -45,6 +45,7 @@ The <action> type attribute can be add,update,fix,remove.
       <!-- FIX -->
       <action                        type="fix" dev="ggregory" due-to="Henri 
Biestro, Gary Gregory">Fix migration documentation to mention Java 11.</action>
       <action issue="FILEUPLOAD-362" type="fix" dev="ggregory" due-to="Kusal 
Kithul-Godage, Gary Gregory">Unable to parse requests for file uploads with 
special characters in filename on Windows.</action>
+      <action                        type="fix" dev="markt"    due-to="Mark 
Thomas">Implement stricter checks for fields using RFC 2231 / RFC 5987. Invalid 
extended values will be ignored.</action>
       <!-- ADD -->
       <!-- UPDATE -->
       <action type="update" dev="ggregory" due-to="Gary Gregory">Bump 
org.apache.commons:commons-parent from 96 to 99.</action>

Reply via email to