quarkusio/quarkus · error · IllegalArgumentException

control character in cookie value

Error message

control character in cookie value

What it means

ServerCookie.maybeQuote2 appends a cookie value to a Set-Cookie header, quoting it when required. If the value contains control characters (CTL chars per the cookie spec, checked by containsCTL), it refuses to emit a malformed cookie and throws IllegalArgumentException instead of silently producing an invalid header.

Source

Thrown at independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/headers/ServerCookie.java:236

    public static boolean alreadyQuoted(String value) {
        if (value == null || value.length() == 0)
            return false;
        return (value.charAt(0) == '\"' && value.charAt(value.length() - 1) == '\"');
    }

    /**
     * Quotes values using rules that vary depending on Cookie version.
     *
     * @param version cookie version
     * @param buf buffer
     * @param value value
     */
    public static void maybeQuote2(int version, StringBuffer buf, String value) {
        if (value == null || value.length() == 0) {
            buf.append("\"\"");
        } else if (containsCTL(value, version))
            throw new IllegalArgumentException("control character in cookie value");
        else if (alreadyQuoted(value)) {
            buf.append('"');
            buf.append(escapeDoubleQuotes(value, 1, value.length() - 1));
            buf.append('"');
        } else if (version == 0 && !isToken(value)) {
            buf.append('"');
            buf.append(escapeDoubleQuotes(value, 0, value.length()));
            buf.append('"');
        } else if (version == 1 && !isToken2(value)) {
            buf.append('"');
            buf.append(escapeDoubleQuotes(value, 0, value.length()));
            buf.append('"');
        } else {
            buf.append(value);
        }
    }

    /**

View on GitHub (pinned to e1c734241f)

Solutions

  1. Sanitize the cookie value: strip or replace control characters before setting it (e.g. value.replaceAll("[\\x00-\\x1F\\x7F]", "")).
  2. URL-encode (URLEncoder.encode / Base64) arbitrary payloads before storing them in cookies and decode on read.
  3. Reduce what you store in the cookie — keep an opaque ID and keep the data server-side.
  4. Catch IllegalArgumentException to reject the value and return a 400-style error instead of crashing.

Example fix

// before
NewCookie c = new NewCookie("session", userInput); // userInput may contain \n
// after
String safe = userInput == null ? "" : userInput.replaceAll("[\\x00-\\x1F\\x7F]", "");
NewCookie c = new NewCookie("session", URLEncoder.encode(safe, StandardCharsets.UTF_8));
Defensive patterns

Strategy: validation

Validate before calling

static String sanitizeCookieValue(String v) {
    if (v == null) return "";
    return v.replaceAll("[\\x00-\\x1F\\x7F]", "");
}
// call: NewCookie c = new NewCookie("name", sanitizeCookieValue(userInput));

Type guard

static boolean isSafeCookieValue(String v) {
    return v != null && v.chars().noneMatch(c -> c < 0x20 || c == 0x7F);
}

Try / catch

try {
    ServerCookie.maybeQuote2(0, buf, value);
} catch (IllegalArgumentException e) {
    throw new BadRequestException("Illegal cookie value");
}

Prevention

When it happens

Trigger: Setting a cookie whose value contains control characters (e.g. \n, \r, \t, or chars < 0x20 / 0x7F), via NewCookie with such a value serialized through ServerCookie, or appending a raw user-input value into a cookie.

Common situations: Echoing unsanitized user input into a cookie value; log fragments or multi-line strings stored in cookies; values copied from headers or JSON containing newlines; header-injection防御 rejecting the value.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/8441de1b846c043d. Report an issue: GitHub.