Skip to content

reject control characters in MediaType parameter values - #8743

Open
arshsmith1 wants to merge 1 commit into
google:masterfrom
arshsmith1:mediatype-param-control-chars
Open

arshsmith1 wants to merge 1 commit into
google:masterfrom
arshsmith1:mediatype-param-control-chars

Conversation

@arshsmith1

Copy link
Copy Markdown
Contributor

MediaType.normalizeParameterValue only required parameter values to be ASCII, which still permits control characters. parse("text/plain; a=\"b\nc\"") is accepted, and withParameter("a", "b\r\nc") is accepted; toString() then writes the raw CR/LF back out (escapeAndQuote backslash-escapes CR but still emits the literal byte, and it never touches LF), so a MediaType built from attacker-influenced parameter values can smuggle CR/LF into a serialized Content-Type header. This rejects ISO control characters at normalizeParameterValue, the single point both parse and withParameter(s) route values through, so no instance can hold one; valid values round-trip unchanged.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a validation check to MediaType.normalizeParameterValue to reject control characters in parameter values. The reviewer identified that the current implementation using javaIsoControl() incorrectly blocks horizontal tabs ( ), which are permitted by RFC 7230. The reviewer provided a fix to exclude tabs from the check and suggested adding a corresponding test case to verify that tabs are allowed.

Comment on lines +1245 to +1248
checkArgument(
javaIsoControl().matchesNoneOf(value),
"parameter values must not contain control characters: %s",
value);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

According to RFC 7230 Section 3.2.6, horizontal tab (\t) is explicitly allowed in quoted-string parameter values (qdtext = HTAB / SP / ...). By using javaIsoControl().matchesNoneOf(value), valid parameter values containing tab characters will be incorrectly rejected.

To remain compliant with the RFC while still preventing header injection/smuggling via CR/LF and other control characters, we should exclude \t from the rejected control characters.

    checkArgument(
        javaIsoControl().and(CharMatcher.isNot('\\t')).matchesNoneOf(value),
        "parameter values must not contain control characters: %s",
        value);

Comment on lines +278 to +284
public void testWithParameter_controlCharacterInParameterValue() {
MediaType mediaType = MediaType.parse("text/plain");
assertThrows(
IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\r\nb"));
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\nb"));
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\u0000b"));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add a test case to verify that horizontal tab (\t) is allowed in parameter values, as it is a valid character according to RFC 7230.

Suggested change
public void testWithParameter_controlCharacterInParameterValue() {
MediaType mediaType = MediaType.parse("text/plain");
assertThrows(
IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\r\nb"));
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\nb"));
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\u0000b"));
}
public void testWithParameter_controlCharacterInParameterValue() {
MediaType mediaType = MediaType.parse("text/plain");
assertThrows(
IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\\r\\nb"));
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\\nb"));
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\\u0000b"));
assertThat(mediaType.withParameter("a", "a\\tb").toString()).isEqualTo("text/plain; a=\"a\\tb\"");
}

@cpovirk

cpovirk commented Oct 15, 2026

Copy link
Copy Markdown
Member

I can take care of the tab handling as part of importing this. (But of course let me know if you see problems with Gemini's proposal—or with #8747 more broadly.)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 package=net type=defect Bug, not working as expected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants