Skip to content

Fix ArrayIndexOutOfBoundsException in Base64Url on padding-only input - #51217

Open
sergioperezcheco wants to merge 2 commits into
keycloak:mainfrom
sergioperezcheco:fix/base64url-padding-only-aioobe
Open

Fix ArrayIndexOutOfBoundsException in Base64Url on padding-only input#51217
sergioperezcheco wants to merge 2 commits into
keycloak:mainfrom
sergioperezcheco:fix/base64url-padding-only-aioobe

Conversation

@sergioperezcheco

Copy link
Copy Markdown

Base64Url.encodeBase64ToBase64Url strips trailing '=' padding with base64.split("=")[0]. When the input is entirely padding (e.g. "=" or "=="), String.split discards trailing empty strings and returns a zero-length array, so the [0] access throws ArrayIndexOutOfBoundsException. This surfaces through Base64Url.decode and JOSEParser.parse when processing malformed JOSE compact tokens that contain padding-only segments.

The fix guards the array access — the first segment is taken only when the array is non-empty, otherwise an empty string is returned, which is the correct Base64Url representation of content that was all padding.

Added Base64UrlTest covering normal inputs, charset conversion, the padding-only edge cases, empty strings, and the decode path.

Fixes #51212

encodeBase64ToBase64Url used base64.split("=")[0] to strip trailing
padding. When the input consists entirely of '=' characters (e.g. "="
or "=="), String.split discards trailing empty strings and returns a
zero-length array, so the [0] access throws ArrayIndexOutOfBoundsException.
This propagated through Base64Url.decode and JOSEParser.parse when
processing malformed JOSE compact tokens with padding-only segments.

Guard the array access: take the first segment only when the array is
non-empty, otherwise return an empty string (the correct Base64Url
representation of content that was all padding).

Fixes keycloak#51212

Signed-off-by: sergioperezcheco <checo520@outlook.com>
Copilot AI review requested due to automatic review settings July 28, 2026 01:12
@sergioperezcheco
sergioperezcheco requested a review from a team as a code owner July 28, 2026 01:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Fixes an ArrayIndexOutOfBoundsException in Base64Url.encodeBase64ToBase64Url when the input is padding-only (e.g. "=", "=="), which can surface when parsing malformed JOSE compact tokens.

Changes:

  • Guarded access to the first element of base64.split("=") to handle padding-only inputs safely.
  • Added unit tests covering normal encoding/decoding, base64 charset conversion, padding-only inputs, and empty strings.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
common/src/main/java/org/keycloak/common/util/Base64Url.java Protects against split returning a zero-length array for padding-only inputs.
common/src/test/java/org/keycloak/common/util/Base64UrlTest.java Adds regression and behavioral tests for encoding/decoding and padding-only edge cases.

Comment on lines +47 to +52
// Remove any trailing '='s. String.split discards trailing empty strings,
// so a padding-only input (e.g. "=" or "==") produces an empty array whose
// first element cannot be accessed. Take the first segment only when the
// array is non-empty; otherwise there is no content before the padding.
String[] parts = base64.split("=");
String s = parts.length > 0 ? parts[0] : "";
@Test
public void decode_normalInput() {
byte[] result = Base64Url.decode("dGVzdA");
assertThat(new String(result), equalTo("test"));
// decode() routes through encodeBase64ToBase64Url, so padded Base64
// input must still work.
byte[] result = Base64Url.decode("dGVzdA==");
assertThat(new String(result), equalTo("test"));
…in tests

Switch encodeBase64ToBase64Url to indexOf('=') + substring as suggested in
review — avoids the regex engine and array allocation of String.split and
still handles padding-only input cleanly. Also pass StandardCharsets.UTF_8
to String constructors in the test assertions instead of relying on the
platform default charset.

Signed-off-by: sergioperezcheco <checo520@outlook.com>
Copilot AI review requested due to automatic review settings July 28, 2026 07:04
@sergioperezcheco

Copy link
Copy Markdown
Author

Updated both points: switched to indexOf('=') + substring so we skip the regex/array allocation entirely, and the test assertions now pass StandardCharsets.UTF_8 explicitly.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

common/src/main/java/org/keycloak/common/util/Base64Url.java:53

  • The explanation about padding-only input is incorrect/misleading: for "=" / "==", indexOf('=') returns 0 (not -1) and substring(0, 0) yields "" (there is no trimming involved). Please adjust the comment to describe the idx == 0 behavior (or remove the -1/trimming explanation) so future readers don’t misunderstand why this fixes the exception.
        // Strip trailing Base64 padding ('=') by cutting at the first '='.
        // indexOf avoids the regex + array allocation of String.split and also
        // handles padding-only input (e.g. "=" or "==") without an
        // ArrayIndexOutOfBoundsException — indexOf returns -1, so we keep the full string,
        // which is empty after trimming when the input was all '=' characters.
        int idx = base64.indexOf('=');
        String s = idx >= 0 ? base64.substring(0, idx) : base64;

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JOSE: Base64Url decoder throws unchecked exception on padding-only input

2 participants