Version in base suite: 2.4.11+~2.4.0-2 Base version: node-sha.js_2.4.11+~2.4.0-2 Target version: node-sha.js_2.4.11+~2.4.0-2+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/n/node-sha.js/node-sha.js_2.4.11+~2.4.0-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/n/node-sha.js/node-sha.js_2.4.11+~2.4.0-2+deb13u1.dsc changelog | 8 + control | 3 copyright | 8 + install | 6 + patches/CVE-2025-9288.patch | 106 ++++++++++++++++++ patches/import-to-buffer.patch | 233 +++++++++++++++++++++++++++++++++++++++++ patches/series | 2 7 files changed, 366 insertions(+) diff -Nru node-sha.js-2.4.11+~2.4.0/debian/changelog node-sha.js-2.4.11+~2.4.0/debian/changelog --- node-sha.js-2.4.11+~2.4.0/debian/changelog 2022-11-21 11:16:07.000000000 +0000 +++ node-sha.js-2.4.11+~2.4.0/debian/changelog 2025-09-14 17:44:33.000000000 +0000 @@ -1,3 +1,11 @@ +node-sha.js (2.4.11+~2.4.0-2+deb13u1) trixie-security; urgency=medium + + * Team upload + * Fix improper input validation vulnerability (Closes: #1111769, CVE-2025-9288) + * Add dependencies to node-get-intrinsic, node-isarray and node-is-typed-array + + -- Yadd Sun, 14 Sep 2025 19:44:33 +0200 + node-sha.js (2.4.11+~2.4.0-2) unstable; urgency=medium [ Debian Janitor ] diff -Nru node-sha.js-2.4.11+~2.4.0/debian/control node-sha.js-2.4.11+~2.4.0/debian/control --- node-sha.js-2.4.11+~2.4.0/debian/control 2022-11-21 11:16:07.000000000 +0000 +++ node-sha.js-2.4.11+~2.4.0/debian/control 2025-09-14 17:41:24.000000000 +0000 @@ -19,7 +19,10 @@ Package: node-sha.js Architecture: all Depends: ${misc:Depends} + , node-get-intrinsic , node-inherits + , node-isarray + , node-is-typed-array , node-safe-buffer (>= 5.0.1) , nodejs:any Provides: ${nodejs:Provides} diff -Nru node-sha.js-2.4.11+~2.4.0/debian/copyright node-sha.js-2.4.11+~2.4.0/debian/copyright --- node-sha.js-2.4.11+~2.4.0/debian/copyright 2022-11-21 11:16:07.000000000 +0000 +++ node-sha.js-2.4.11+~2.4.0/debian/copyright 2025-09-14 17:33:11.000000000 +0000 @@ -18,6 +18,14 @@ Copyright: 2017 Bastien Roucariès License: Expat +Files: debian/patches/import-to-buffer.patch +Copyright: 2016, Mathias Buus + 2023-2024, Jordan Harband +License: Expat +Comment: installed into /usr/share/nodejs/sha.js/node_modules/ + to-buffer: (c) 2016, Mathias Buus + others: 2023-2024, Jordan Harband + Files: types-*/* Copyright: Microsoft Corporation License: Expat diff -Nru node-sha.js-2.4.11+~2.4.0/debian/install node-sha.js-2.4.11+~2.4.0/debian/install --- node-sha.js-2.4.11+~2.4.0/debian/install 1970-01-01 00:00:00.000000000 +0000 +++ node-sha.js-2.4.11+~2.4.0/debian/install 2025-09-14 17:30:17.000000000 +0000 @@ -0,0 +1,6 @@ +node_modules/call-bind-apply-helpers/* usr/share/nodejs/sha.js/node_modules/call-bind-apply-helpers +node_modules/call-bound.js usr/share/nodejs/sha.js/node_modules/ +node_modules/es-errors/* usr/share/nodejs/sha.js/node_modules/es-errors/ +node_modules/es-errors/type.js usr/share/nodejs/sha.js/node_modules/ +node_modules/to-buffer.js usr/share/nodejs/sha.js/node_modules/ +node_modules/typed-array-buffer.js usr/share/nodejs/sha.js/node_modules/ diff -Nru node-sha.js-2.4.11+~2.4.0/debian/patches/CVE-2025-9288.patch node-sha.js-2.4.11+~2.4.0/debian/patches/CVE-2025-9288.patch --- node-sha.js-2.4.11+~2.4.0/debian/patches/CVE-2025-9288.patch 1970-01-01 00:00:00.000000000 +0000 +++ node-sha.js-2.4.11+~2.4.0/debian/patches/CVE-2025-9288.patch 2025-09-14 17:12:22.000000000 +0000 @@ -0,0 +1,106 @@ +Description: Support multi-byte wide typed arrays +Author: Nikita Skovoroda +Origin: upstream, https://github.com/browserify/sha.js/commit/f2a258e9 +Bug: https://github.com/browserify/sha.js/pull/78 +Bug-Debian: https://bugs.debian.org/1111769 +Forwarded: not-needed +Applied-Upstream: 2.4.12, https://github.com/browserify/sha.js/pull/78 +Reviewed-By: Xavier Guimard +Last-Update: 2025-09-14 + +--- a/hash.js ++++ b/hash.js +@@ -1,4 +1,5 @@ + var Buffer = require('safe-buffer').Buffer ++var toBuffer = require('to-buffer'); + + // prototype class for hash functions + function Hash (blockSize, finalSize) { +@@ -9,10 +10,7 @@ + } + + Hash.prototype.update = function (data, enc) { +- if (typeof data === 'string') { +- enc = enc || 'utf8' +- data = Buffer.from(data, enc) +- } ++ data = toBuffer(data, enc || 'utf8') + + var block = this._block + var blockSize = this._blockSize +--- a/test/test.js ++++ b/test/test.js +@@ -2,6 +2,12 @@ + var tape = require('tape') + var Sha1 = require('../').sha1 + ++var nodeSupportsUint16 = false; ++try { ++ crypto.createHash('sha1').update(new Uint16Array()); ++ nodeSupportsUint16 = true; ++} catch (err) {} ++ + var inputs = [ + ['', 'ascii'], + ['abc', 'ascii'], +@@ -11,8 +17,10 @@ + ['123456789abcdef123456789abcdef123456789abcdef123456789ab', 'ascii'], + ['0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde', 'ascii'], + ['0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', 'ascii'], +- ['foobarbaz', 'ascii'] +-] ++ ['foobarbaz', 'ascii'], ++ [Buffer.from('buffer')], ++ nodeSupportsUint16 ? [new Uint16Array([1, 2, 3])] : null ++].filter(Boolean); + + tape("hash is the same as node's crypto", function (t) { + inputs.forEach(function (v) { +@@ -31,7 +39,7 @@ + var _hash = crypto.createHash('sha1') + + for (var i = 0; i < v[0].length; i = (i + 1) * 2) { +- var s = v[0].substring(i, (i + 1) * 2) ++ var s = v[0].slice(i, (i + 1) * 2); + hash.update(s, v[1]) + _hash.update(s, v[1]) + } +@@ -70,7 +78,7 @@ + var _hash = crypto.createHash('sha1') + + for (var i = 0; i < v[0].length; i = (i + 1) * 2) { +- var s = v[0].substring(i, (i + 1) * 2) ++ var s = v[0].slice(i, (i + 1) * 2); + hash.update(Buffer.from(s, 'ascii').toString('hex'), 'hex') + _hash.update(Buffer.from(s, 'ascii').toString('hex'), 'hex') + } +@@ -84,6 +92,29 @@ + t.end() + }) + ++tape('throws on invalid input', function (t) { ++ var invalid = [ ++ {}, // non-arrayish ++ { length: 20 }, // undefined values ++ [NaN], // non-numbers ++ [[]], // non-numbers ++ [1, 1.5], // non-integers ++ [1, 256], // out of bounds ++ [-1, 0] // out of bounds ++ ]; ++ ++ invalid.forEach(function (input) { ++ var hash = new Sha1(); ++ ++ t['throws'](function () { ++ hash.update(input); ++ hash.digest('hex'); ++ }); ++ }); ++ ++ t.end(); ++}); ++ + tape('call digest for more than MAX_UINT32 bits of data', function (t) { + var _hash = crypto.createHash('sha1') + var hash = new Sha1() diff -Nru node-sha.js-2.4.11+~2.4.0/debian/patches/import-to-buffer.patch node-sha.js-2.4.11+~2.4.0/debian/patches/import-to-buffer.patch --- node-sha.js-2.4.11+~2.4.0/debian/patches/import-to-buffer.patch 1970-01-01 00:00:00.000000000 +0000 +++ node-sha.js-2.4.11+~2.4.0/debian/patches/import-to-buffer.patch 2025-09-14 17:31:39.000000000 +0000 @@ -0,0 +1,233 @@ +Description: import to-buffer, needed to fix CVE-2025-9288 +Author: Yadd +Forwarded: not-needed +Last-Update: 2025-09-14 + +--- /dev/null ++++ b/node_modules/call-bind-apply-helpers/actualApply.js +@@ -0,0 +1,10 @@ ++'use strict'; ++ ++var bind = require('function-bind'); ++ ++var $apply = require('./functionApply'); ++var $call = require('./functionCall'); ++var $reflectApply = require('./reflectApply'); ++ ++/** @type {import('./actualApply')} */ ++module.exports = $reflectApply || bind.call($call, $apply); +--- /dev/null ++++ b/node_modules/call-bind-apply-helpers/applyBind.js +@@ -0,0 +1,10 @@ ++'use strict'; ++ ++var bind = require('function-bind'); ++var $apply = require('./functionApply'); ++var actualApply = require('./actualApply'); ++ ++/** @type {import('./applyBind')} */ ++module.exports = function applyBind() { ++ return actualApply(bind, $apply, arguments); ++}; +--- /dev/null ++++ b/node_modules/call-bind-apply-helpers/functionApply.js +@@ -0,0 +1,4 @@ ++'use strict'; ++ ++/** @type {import('./functionApply')} */ ++module.exports = Function.prototype.apply; +--- /dev/null ++++ b/node_modules/call-bind-apply-helpers/functionCall.js +@@ -0,0 +1,4 @@ ++'use strict'; ++ ++/** @type {import('./functionCall')} */ ++module.exports = Function.prototype.call; +--- /dev/null ++++ b/node_modules/call-bind-apply-helpers/index.js +@@ -0,0 +1,15 @@ ++'use strict'; ++ ++var bind = require('function-bind'); ++var $TypeError = require('es-errors/type'); ++ ++var $call = require('./functionCall'); ++var $actualApply = require('./actualApply'); ++ ++/** @type {(args: [Function, thisArg?: unknown, ...args: unknown[]]) => Function} TODO FIXME, find a way to use import('.') */ ++module.exports = function callBindBasic(args) { ++ if (args.length < 1 || typeof args[0] !== 'function') { ++ throw new $TypeError('a function is required'); ++ } ++ return $actualApply(bind, $call, args); ++}; +--- /dev/null ++++ b/node_modules/call-bind-apply-helpers/reflectApply.js +@@ -0,0 +1,4 @@ ++'use strict'; ++ ++/** @type {import('./reflectApply')} */ ++module.exports = typeof Reflect !== 'undefined' && Reflect && Reflect.apply; +--- /dev/null ++++ b/node_modules/call-bound.js +@@ -0,0 +1,19 @@ ++'use strict'; ++ ++var GetIntrinsic = require('get-intrinsic'); ++ ++var callBindBasic = require('call-bind-apply-helpers'); ++ ++/** @type {(thisArg: string, searchString: string, position?: number) => number} */ ++var $indexOf = callBindBasic([GetIntrinsic('%String.prototype.indexOf%')]); ++ ++/** @type {import('.')} */ ++module.exports = function callBoundIntrinsic(name, allowMissing) { ++ /* eslint no-extra-parens: 0 */ ++ ++ var intrinsic = /** @type {(this: unknown, ...args: unknown[]) => unknown} */ (GetIntrinsic(name, !!allowMissing)); ++ if (typeof intrinsic === 'function' && $indexOf(name, '.prototype.') > -1) { ++ return callBindBasic(/** @type {const} */ ([intrinsic])); ++ } ++ return intrinsic; ++}; +--- /dev/null ++++ b/node_modules/es-errors/type.js +@@ -0,0 +1,4 @@ ++'use strict'; ++ ++/** @type {import('./type')} */ ++module.exports = TypeError; +--- /dev/null ++++ b/node_modules/to-buffer.js +@@ -0,0 +1,109 @@ ++'use strict'; ++ ++var Buffer = require('safe-buffer').Buffer; ++var isArray = require('isarray'); ++var typedArrayBuffer = require('typed-array-buffer'); ++ ++var isView = ArrayBuffer.isView || function isView(obj) { ++ try { ++ typedArrayBuffer(obj); ++ return true; ++ } catch (e) { ++ return false; ++ } ++}; ++ ++var useUint8Array = typeof Uint8Array !== 'undefined'; ++var useArrayBuffer = typeof ArrayBuffer !== 'undefined' ++ && typeof Uint8Array !== 'undefined'; ++var useFromArrayBuffer = useArrayBuffer && (Buffer.prototype instanceof Uint8Array || Buffer.TYPED_ARRAY_SUPPORT); ++ ++module.exports = function toBuffer(data, encoding) { ++ /* ++ * No need to do anything for exact instance ++ * This is only valid when safe-buffer.Buffer === buffer.Buffer, i.e. when Buffer.from/Buffer.alloc existed ++ */ ++ if (data instanceof Buffer) { ++ return data; ++ } ++ ++ if (typeof data === 'string') { ++ return Buffer.from(data, encoding); ++ } ++ ++ /* ++ * Wrap any TypedArray instances and DataViews ++ * Makes sense only on engines with full TypedArray support -- let Buffer detect that ++ */ ++ if (useArrayBuffer && isView(data)) { ++ // Bug in Node.js <6.3.1, which treats this as out-of-bounds ++ if (data.byteLength === 0) { ++ return Buffer.alloc(0); ++ } ++ ++ // When Buffer is based on Uint8Array, we can just construct it from ArrayBuffer ++ if (useFromArrayBuffer) { ++ var res = Buffer.from(data.buffer, data.byteOffset, data.byteLength); ++ /* ++ * Recheck result size, as offset/length doesn't work on Node.js <5.10 ++ * We just go to Uint8Array case if this fails ++ */ ++ if (res.byteLength === data.byteLength) { ++ return res; ++ } ++ } ++ ++ // Convert to Uint8Array bytes and then to Buffer ++ var uint8 = data instanceof Uint8Array ? data : new Uint8Array(data.buffer, data.byteOffset, data.byteLength); ++ var result = Buffer.from(uint8); ++ ++ /* ++ * Let's recheck that conversion succeeded ++ * We have .length but not .byteLength when useFromArrayBuffer is false ++ */ ++ if (result.length === data.byteLength) { ++ return result; ++ } ++ } ++ ++ /* ++ * Uint8Array in engines where Buffer.from might not work with ArrayBuffer, just copy over ++ * Doesn't make sense with other TypedArray instances ++ */ ++ if (useUint8Array && data instanceof Uint8Array) { ++ return Buffer.from(data); ++ } ++ ++ var isArr = isArray(data); ++ if (isArr) { ++ for (var i = 0; i < data.length; i += 1) { ++ var x = data[i]; ++ if ( ++ typeof x !== 'number' ++ || x < 0 ++ || x > 255 ++ || ~~x !== x // NaN and integer check ++ ) { ++ throw new RangeError('Array items must be numbers in the range 0-255.'); ++ } ++ } ++ } ++ ++ /* ++ * Old Buffer polyfill on an engine that doesn't have TypedArray support ++ * Also, this is from a different Buffer polyfill implementation then we have, as instanceof check failed ++ * Convert to our current Buffer implementation ++ */ ++ if ( ++ isArr || ( ++ Buffer.isBuffer(data) ++ && data.constructor ++ && typeof data.constructor.isBuffer === 'function' ++ && data.constructor.isBuffer(data) ++ ) ++ ) { ++ return Buffer.from(data); ++ } ++ ++ throw new TypeError('The "data" argument must be a string, an Array, a Buffer, a Uint8Array, or a DataView.'); ++}; +--- /dev/null ++++ b/node_modules/typed-array-buffer.js +@@ -0,0 +1,19 @@ ++'use strict'; ++ ++var $TypeError = require('es-errors/type'); ++ ++var callBound = require('call-bound'); ++ ++/** @type {undefined | ((thisArg: import('.').TypedArray) => Buffer)} */ ++var $typedArrayBuffer = callBound('TypedArray.prototype.buffer', true); ++ ++var isTypedArray = require('is-typed-array'); ++ ++/** @type {import('.')} */ ++// node <= 0.10, < 0.11.4 has a nonconfigurable own property instead of a prototype getter ++module.exports = $typedArrayBuffer || function typedArrayBuffer(x) { ++ if (!isTypedArray(x)) { ++ throw new $TypeError('Not a Typed Array'); ++ } ++ return x.buffer; ++}; diff -Nru node-sha.js-2.4.11+~2.4.0/debian/patches/series node-sha.js-2.4.11+~2.4.0/debian/patches/series --- node-sha.js-2.4.11+~2.4.0/debian/patches/series 2022-11-21 11:16:07.000000000 +0000 +++ node-sha.js-2.4.11+~2.4.0/debian/patches/series 2025-09-14 17:33:23.000000000 +0000 @@ -1,2 +1,4 @@ 0001-Fix-testsuite.patch 0002-Fix-FTBFS-in-32-bits-arch.patch +CVE-2025-9288.patch +import-to-buffer.patch