From ae80c0821fa44c46bbb904ed553b405853daf280 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 31 Mar 2022 10:42:41 +0200 Subject: [PATCH] buffer: fix `atob` input validation Fixes: https://github.com/nodejs/node/issues/42530 --- lib/buffer.js | 26 +++++++++++++++++++++++--- test/parallel/test-btoa-atob.js | 2 ++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 8e29ac1822af82..93fd3ca9e93859 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -23,8 +23,10 @@ const { Array, + ArrayFrom, ArrayIsArray, ArrayPrototypeForEach, + ArrayPrototypeIncludes, MathFloor, MathMin, MathTrunc, @@ -1230,8 +1232,25 @@ function btoa(input) { return buf.toString('base64'); } -const kBase64Digits = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; +// Refs: https://infra.spec.whatwg.org/#forgiving-base64-decode +const kForgivingBase64AllowedChars = [ + // ASCII whitespace + // Refs: https://infra.spec.whatwg.org/#ascii-whitespace + 0x09, 0x0A, 0x0C, 0x0D, 0x20, + + // Uppercase letters + ...ArrayFrom({ length: 26 }, (_, i) => StringPrototypeCharCodeAt('A') + i), + + // Lowercase letters + ...ArrayFrom({ length: 26 }, (_, i) => StringPrototypeCharCodeAt('a') + i), + + // Decimal digits + ...ArrayFrom({ length: 10 }, (_, i) => StringPrototypeCharCodeAt('0') + i), + + 0x2b, // + + 0x2f, // / + 0x3d, // = +]; function atob(input) { // The implementation here has not been performance optimized in any way and @@ -1242,7 +1261,8 @@ function atob(input) { } input = `${input}`; for (let n = 0; n < input.length; n++) { - if (!kBase64Digits.includes(input[n])) + if (!ArrayPrototypeIncludes(kForgivingBase64AllowedChars, + StringPrototypeCharCodeAt(input, n))) throw lazyDOMException('Invalid character', 'InvalidCharacterError'); } return Buffer.from(input, 'base64').toString('latin1'); diff --git a/test/parallel/test-btoa-atob.js b/test/parallel/test-btoa-atob.js index 162406dd9f6b50..a13a32370c44cf 100644 --- a/test/parallel/test-btoa-atob.js +++ b/test/parallel/test-btoa-atob.js @@ -12,3 +12,5 @@ strictEqual(globalThis.btoa, buffer.btoa); // Throws type error on no argument passed throws(() => buffer.atob(), /TypeError/); throws(() => buffer.btoa(), /TypeError/); + +strictEqual(atob(' '), '');