From ae80c0821fa44c46bbb904ed553b405853daf280 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 31 Mar 2022 10:42:41 +0200 Subject: [PATCH 1/3] 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(' '), ''); From 3be9788b8a4f58053ff9c3b70f4c908f8476f507 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 31 Mar 2022 10:45:23 +0200 Subject: [PATCH 2/3] fixup! buffer: fix `atob` input validation --- lib/buffer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 93fd3ca9e93859..773d56572aa2a4 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -1247,9 +1247,9 @@ const kForgivingBase64AllowedChars = [ // Decimal digits ...ArrayFrom({ length: 10 }, (_, i) => StringPrototypeCharCodeAt('0') + i), - 0x2b, // + - 0x2f, // / - 0x3d, // = + 0x2B, // + + 0x2F, // / + 0x3D, // = ]; function atob(input) { From a63982f305ed84a8094065f8e24021a589fef148 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 31 Mar 2022 11:07:21 +0200 Subject: [PATCH 3/3] fixup! buffer: fix `atob` input validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michaƫl Zasso --- test/parallel/test-btoa-atob.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/parallel/test-btoa-atob.js b/test/parallel/test-btoa-atob.js index a13a32370c44cf..64f53671030ba0 100644 --- a/test/parallel/test-btoa-atob.js +++ b/test/parallel/test-btoa-atob.js @@ -14,3 +14,4 @@ throws(() => buffer.atob(), /TypeError/); throws(() => buffer.btoa(), /TypeError/); strictEqual(atob(' '), ''); +strictEqual(atob(' YW\tJ\njZA=\r= '), 'abcd');