From f5146d04f86e32e39b1dc7a9214bfee0caa4934d Mon Sep 17 00:00:00 2001 From: Gaurav Kaushik Date: Mon, 18 Aug 2025 14:50:12 -0700 Subject: [PATCH 1/3] Fix for CVE-2023-30533 --- bits/02_codepage.js | 5 +++++ bits/18_cfb.js | 2 +- bits/56_cmntcommon.js | 1 + bits/71_wbcommon.js | 19 +++++++++++-------- bits/79_html.js | 2 +- bits/87_read.js | 8 +++++++- 6 files changed, 26 insertions(+), 11 deletions(-) diff --git a/bits/02_codepage.js b/bits/02_codepage.js index c9e3da8..bbad999 100644 --- a/bits/02_codepage.js +++ b/bits/02_codepage.js @@ -45,6 +45,11 @@ function utf16leread(data/*:string*/)/*:string*/ { for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i) + (data.charCodeAt(2*i+1)<<8)); return o.join(""); } +function utf16lereadu(data/*:Uint8Array*/)/*:string*/ { + var o/*:Array*/ = []; + for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data[2*i] + (data[2*i+1]<<8)); + return o.join(""); +} function utf16beread(data/*:string*/)/*:string*/ { var o/*:Array*/ = []; for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i+1) + (data.charCodeAt(2*i)<<8)); diff --git a/bits/18_cfb.js b/bits/18_cfb.js index 4896c18..89e14db 100644 --- a/bits/18_cfb.js +++ b/bits/18_cfb.js @@ -73,7 +73,7 @@ function slice_by_16_tables(T) { for(c = 256 + n; c < 4096; c += 256) v = table[c] = (v >>> 8) ^ T[v & 0xFF]; } var out = []; - for(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256); + for(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' && typeof table.subarray == "function" ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256); return out; } var TT = slice_by_16_tables(T0); diff --git a/bits/56_cmntcommon.js b/bits/56_cmntcommon.js index c87f857..868b6b8 100644 --- a/bits/56_cmntcommon.js +++ b/bits/56_cmntcommon.js @@ -3,6 +3,7 @@ function sheet_insert_comments(sheet, comments/*:Array*/, threaded/* var cell/*:Cell*/; comments.forEach(function(comment) { var r = decode_cell(comment.ref); + if(r.r < 0 || r.c < 0) return; if(dense) { if(!sheet[r.r]) sheet[r.r] = []; cell = sheet[r.r][r.c]; diff --git a/bits/71_wbcommon.js b/bits/71_wbcommon.js index fa513e6..02e4107 100644 --- a/bits/71_wbcommon.js +++ b/bits/71_wbcommon.js @@ -115,14 +115,17 @@ function safe1904(wb/*:Workbook*/)/*:string*/ { var badchars = /*#__PURE__*/"][*?\/\\".split(""); function check_ws_name(n/*:string*/, safe/*:?boolean*/)/*:boolean*/ { - if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); } - var _good = true; - badchars.forEach(function(c) { - if(n.indexOf(c) == -1) return; - if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]"); - _good = false; - }); - return _good; + try { + if(n == "") throw new Error("Sheet name cannot be blank"); + if(n.length > 31) throw new Error("Sheet name cannot exceed 31 chars"); + if(n.charCodeAt(0) == 0x27 || n.charCodeAt(n.length - 1) == 0x27) throw new Error("Sheet name cannot start or end with apostrophe (')"); + if(n.toLowerCase() == "history") throw new Error("Sheet name cannot be 'History'"); + badchars.forEach(function(c) { + if(n.indexOf(c) == -1) return; + throw new Error("Sheet name cannot contain : \\ / ? * [ ]"); + }); + } catch(e) { if(safe) return false; throw e; } + return true; } function check_wb_names(N, S, codes) { N.forEach(function(n,i) { diff --git a/bits/79_html.js b/bits/79_html.js index 76482ed..4c1a806 100644 --- a/bits/79_html.js +++ b/bits/79_html.js @@ -81,7 +81,7 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT sp["data-t"] = cell && cell.t || 'z'; if(cell.v != null) sp["data-v"] = cell.v; if(cell.z != null) sp["data-z"] = cell.z; - if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '' + w + ''; + if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '' + w + ''; } sp.id = (o.id || "sjs") + "-" + coord; oo.push(writextag('td', w, sp)); diff --git a/bits/87_read.js b/bits/87_read.js index c55302e..64baefb 100644 --- a/bits/87_read.js +++ b/bits/87_read.js @@ -50,7 +50,13 @@ function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { function read_utf16(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { var d = data; if(o.type == 'base64') d = Base64_decode(d); - d = $cptable.utils.decode(1200, d.slice(2), 'str'); + if(typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) d = new Uint8Array(data); + d = typeof $cptable !== "undefined" ? $cptable.utils.decode(1200, d.slice(2), 'str') : ( + (has_buf && Buffer.isBuffer(data)) ? data.slice(2).toString("utf16le") : + (typeof Uint8Array !== "undefined" && d instanceof Uint8Array) ? ( + typeof TextDecoder !== "undefined" ? new TextDecoder("utf-16le").decode(d.slice(2)) : utf16lereadu(d.slice(2)) + ) : utf16leread(d.slice(2)) + ); o.type = "binary"; return read_plaintext(d, o); } -- 2.34.1 From 2a9a6f2390bb9acafaab9b326e2eadc8a0f88147 Mon Sep 17 00:00:00 2001 From: Gaurav Kaushik Date: Mon, 18 Aug 2025 22:45:54 -0700 Subject: [PATCH 2/3] Added unit test --- test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test.js b/test.js index 21cd011..ff491fd 100644 --- a/test.js +++ b/test.js @@ -1769,6 +1769,21 @@ describe('invalid files', function() { wb.SheetNames.push(wb.SheetNames[0]); assert.throws(function() { X.write(wb, {type:'binary'}); }); }); + it('should fail if sheet name is not valid', function() { + var names = [ + "", // cannot be blank + "abcdefghijklmnopqrstuvwxyz1234567890", // cannot exceed 31 chars + "'sheetjs", "sheetjs'", // cannot start or end with apostrophe + "History", // cannot be History + "Sheet:JS", "Sheet]JS", "Sheet[JS", "Sheet*JS", // bad characters + "Sheet?JS", "Sheet\\JS", "Sheet\/JS" + ]; + names.forEach(function(n) { assert.throws(function() { + var wb = { SheetNames: [n], Sheets: {} }; + wb.Sheets[n] = X.utils.aoa_to_sheet([["SheetJS"]]); + X.write(wb, {type:"binary", bookType:"xlsx"}); + }); }); + }); }); }); -- 2.34.1 From ae952cd69da8e5ebaa7728fc30e3ac35daba895d Mon Sep 17 00:00:00 2001 From: Gaurav Kaushik Date: Wed, 20 Aug 2025 09:33:08 -0700 Subject: [PATCH 3/3] Updated the code to add : --- bits/71_wbcommon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bits/71_wbcommon.js b/bits/71_wbcommon.js index 02e4107..ee07ea8 100644 --- a/bits/71_wbcommon.js +++ b/bits/71_wbcommon.js @@ -113,7 +113,7 @@ function safe1904(wb/*:Workbook*/)/*:string*/ { return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; } -var badchars = /*#__PURE__*/"][*?\/\\".split(""); +var badchars = /*#__PURE__*/":][*?\/\\".split(""); function check_ws_name(n/*:string*/, safe/*:?boolean*/)/*:boolean*/ { try { if(n == "") throw new Error("Sheet name cannot be blank"); -- 2.34.1