Compare commits

..
Author SHA1 Message Date
fba3fb4ead fix: resolve audit/license failures (#784)
* fix: resolve brace-expansion high-severity vulnerability, refresh license cache, rebuild dist

- Regenerated package-lock.json to pick up brace-expansion@5.0.9 (fixes
  GHSA-rgw5-rvv9-x895, a DoS via unbounded intermediate arrays), which
  is already permitted by minimatch's existing ^5.0.8 semver range.
- Refreshed .licenses/npm cache to match the updated dependency tree.
- Added minimatch to the licensed.yml reviewed list: its detected
  license text doesn't cleanly match Blue Oak 1.0.0, which is already
  in the allowed list.
- Rebuilt dist/setup and dist/cache-save from source.

npm audit --audit-level=high now reports 0 vulnerabilities;
licensed status reports 0 errors; npm run pre-checkin passes locally.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: narrow audit dependency updates

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-19 10:06:05 -05:00
7 changed files with 830 additions and 210 deletions
@@ -1,6 +1,6 @@
--- ---
name: brace-expansion name: brace-expansion
version: 1.1.16 version: 1.1.18
type: npm type: npm
summary: Brace expansion as known from sh/bash summary: Brace expansion as known from sh/bash
homepage: https://github.com/juliangruber/brace-expansion homepage: https://github.com/juliangruber/brace-expansion
@@ -1,6 +1,6 @@
--- ---
name: brace-expansion name: brace-expansion
version: 5.0.8 version: 5.0.9
type: npm type: npm
summary: Brace expansion as known from sh/bash summary: Brace expansion as known from sh/bash
homepage: homepage:
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: undici name: undici
version: 6.27.0 version: 6.28.0
type: npm type: npm
summary: An HTTP/1.1 client, written from scratch for Node.js summary: An HTTP/1.1 client, written from scratch for Node.js
homepage: https://undici.nodejs.org homepage: https://undici.nodejs.org
+390 -93
View File
@@ -84,6 +84,20 @@ var escClose = '\0CLOSE'+Math.random()+'\0';
var escComma = '\0COMMA'+Math.random()+'\0'; var escComma = '\0COMMA'+Math.random()+'\0';
var escPeriod = '\0PERIOD'+Math.random()+'\0'; var escPeriod = '\0PERIOD'+Math.random()+'\0';
var EXPANSION_MAX = 100000
// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An
// input like `'{a,b}'.repeat(1500)` stays under that count - its output is
// truncated to 100k results - while making every result ~1500 characters
// long. The result set, and the intermediate arrays built while combining
// brace sets, then grow large enough to exhaust memory and crash the process
// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of
// characters the accumulator may hold at any point, so memory stays flat no
// matter how many brace groups are chained. The limit sits well above any
// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
// characters) so legitimate input is unaffected.
var EXPANSION_MAX_LENGTH = 4000000
function numeric(str) { function numeric(str) {
return parseInt(str, 10) == str return parseInt(str, 10) == str
? parseInt(str, 10) ? parseInt(str, 10)
@@ -142,7 +156,8 @@ function expandTop(str, options) {
return []; return [];
options = options || {}; options = options || {};
var max = options.max == null ? Infinity : options.max; var max = options.max == null ? EXPANSION_MAX : options.max;
var maxLength = options.maxLength == null ? EXPANSION_MAX_LENGTH : options.maxLength;
// I don't know why Bash 4.3 does this, but it does. // I don't know why Bash 4.3 does this, but it does.
// Anything starting with {} will have the first two bytes preserved // Anything starting with {} will have the first two bytes preserved
@@ -154,7 +169,7 @@ function expandTop(str, options) {
str = '\\{\\}' + str.substr(2); str = '\\{\\}' + str.substr(2);
} }
return expand(escapeBraces(str), max, true).map(unescapeBraces); return expand(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
} }
function identity(e) { function identity(e) {
@@ -175,15 +190,155 @@ function gte(i, y) {
return i >= y; return i >= y;
} }
function expand(str, max, isTop) { // Build `{ acc[a] + pre + values[v] }` for every combination, capping the
var expansions = []; // number of results at `max` and the total number of characters at `maxLength`.
// This is the one place output grows, so bounding it here keeps the single
// accumulator - and therefore memory - flat regardless of how many brace groups
// are combined (CVE-2026-14257).
//
// `base[a]` is the length of the part of `acc[a]` that predates the current
// empty-drop baseline (see `expand`). The matching baselines for the results
// are appended to `outBase`, which the caller carries forward alongside them.
function combine(
acc,
base,
pre,
values,
max,
maxLength,
dropEmpties,
outBase
) {
var out = []
var length = 0
for (var a = 0; a < acc.length; a++) {
for (var v = 0; v < values.length; v++) {
if (out.length >= max) return out
var expansion = acc[a] + pre + values[v]
// Bash drops empty results at the top level. Skip them before they count
// against `max`, so `max` bounds the number of *kept* results. "Empty"
// means "adds nothing past the baseline", not "empty overall".
if (dropEmpties && expansion.length === base[a]) continue
if (length + expansion.length > maxLength) return out
out.push(expansion)
outBase.push(base[a])
length += expansion.length
}
}
return out
}
// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
// sequence body.
function expandSequence(
body,
isAlphaSequence,
max,
maxLength
) {
var n = body.split(/\.\./)
var N = []
// A sequence body always splits into two or three parts, but the compiler
// can't know that.
/* c8 ignore start */
if (n[0] === undefined || n[1] === undefined) {
return N
}
/* c8 ignore stop */
var x = numeric(n[0])
var y = numeric(n[1])
var width = Math.max(n[0].length, n[1].length)
var incr =
n.length === 3 && n[2] !== undefined ?
Math.max(Math.abs(numeric(n[2])), 1)
: 1
var test = lte
var reverse = y < x
if (reverse) {
incr *= -1
test = gte
}
var pad = n.some(isPadded)
var length = 0
for (var i = x; test(i, y) && N.length < max; i += incr) {
var c
if (isAlphaSequence) {
c = String.fromCharCode(i)
if (c === '\\') {
c = ''
}
} else {
c = String(i)
if (pad) {
var need = width - c.length
if (need > 0) {
var z = new Array(need + 1).join('0')
if (i < 0) {
c = '-' + z + c.slice(1)
} else {
c = z + c
}
}
}
}
if (length + c.length > maxLength) break
N.push(c)
length += c.length
}
return N
}
function expand(
str,
max,
maxLength,
isTop
) {
// Consume the string's top-level brace groups left to right, threading a
// running set of combined prefixes (`acc`). Expanding the tail iteratively -
// rather than recursing on `m.post` once per group - keeps the native stack
// depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no
// longer overflow the stack, and leaves a single accumulator whose size
// `maxLength` bounds directly (CVE-2026-14257).
var acc = ['']
// Bash drops empty results, but only when the *first* group of the run is a
// comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
// is on the final strings, so it is applied to whichever `combine` produces
// them (the one with no brace set left in the tail).
//
// The old implementation recursed on `m.post`, so the drop tested only the
// expansion of the current call's substring. The `{a},b}` rewrite below turns
// `isTop` back on part-way through a string, starting a fresh such run, so
// the drop must ignore whatever `acc` already holds from earlier groups.
// `accBase[a]` records how much of `acc[a]` predates the current run;
// `combine` treats an expansion as empty when it adds nothing past that.
var accBase = [0]
var dropEmpties = false
var firstGroup = true
var nextBase
// The `{a},b}` rewrite below restarts expansion on a rewritten string with
// the same `max` and `isTop = true`. Loop instead of recursing so a long run
// of non-expanding `{}` groups can't exhaust the call stack.
for (;;) { for (;;) {
var m = balanced('{', '}', str); var m = balanced('{', '}', str);
if (!m || /\$$/.test(m.pre)) return [str];
// No brace set left: the rest of the string is literal.
if (!m) {
return combine(acc, accBase, str, [''], max, maxLength, dropEmpties, [])
}
// no need to expand pre, since it is guaranteed to be free of brace-sets
var pre = m.pre;
// For compatibility reasons, `${` is not eligible for brace expansion, and
// on the 1.x line it suppresses expansion of the rest of the string too:
// the whole remainder is literal. The 2.x and 5.x lines instead keep
// expanding the tail, which is what bash does, but changing that here would
// be a breaking change for 1.x consumers. Routed through `combine` so the
// result is still bounded by `max` and `maxLength`.
if (/\$$/.test(pre)) {
return combine(acc, accBase, str, [''], max, maxLength, dropEmpties, [])
}
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
@@ -193,94 +348,112 @@ function expand(str, max, isTop) {
// {a},b} // {a},b}
if (m.post.match(/,(?!,).*\}/)) { if (m.post.match(/,(?!,).*\}/)) {
str = m.pre + '{' + m.body + escClose + m.post; str = m.pre + '{' + m.body + escClose + m.post;
// The rewritten string is expanded as if it were a fresh top-level one,
// so start a new empty-drop run: anchor the baseline at what `acc`
// holds now, and let the next expanding group decide whether to drop.
isTop = true isTop = true
firstGroup = true
dropEmpties = false
accBase = []
for (var b = 0; b < acc.length; b++) {
accBase.push(acc[b].length)
}
continue continue
} }
return [str]; // Nothing here expands, so the whole remaining string is literal.
return combine(
acc,
accBase,
pre + '{' + m.body + '}' + m.post,
[''],
max,
maxLength,
dropEmpties,
[]
)
} }
var n; if (firstGroup) {
dropEmpties = isTop && !isSequence
firstGroup = false
}
var values;
if (isSequence) { if (isSequence) {
n = m.body.split(/\.\./); values = expandSequence(m.body, isAlphaSequence, max, maxLength);
} else { } else {
n = parseCommaParts(m.body); var n = parseCommaParts(m.body);
if (n.length === 1) { if (n.length === 1 && n[0] !== undefined) {
// x{{a,b}}y ==> x{a}y x{b}y // x{{a,b}}y ==> x{a}y x{b}y
n = expand(n[0], max, false).map(embrace); n = expand(n[0], max, maxLength, false).map(embrace);
//XXX is this necessary? Can't seem to hit it in tests.
/* c8 ignore start */
if (n.length === 1) { if (n.length === 1) {
var post = m.post.length nextBase = []
? expand(m.post, max, false) acc = combine(
: ['']; acc,
return post.map(function(p) { accBase,
return m.pre + n[0] + p; pre + n[0],
}); [''],
max,
maxLength,
dropEmpties && !m.post.length,
nextBase
)
accBase = nextBase
if (!m.post.length) break
str = m.post
continue
}
/* c8 ignore stop */
}
// Values that `combine` is going to drop as empty produce no result, so
// they must not count against `max` - otherwise `{a,,b}` with `max: 2`
// would stop at `['a', '']` and yield one result instead of two. Skipping
// them outright keeps `values` bounded while leaving `max` a bound on
// *kept* results. A value is dropped when it adds nothing past the
// baseline, which is what `combine` tests.
var dropsEmpties = dropEmpties && !m.post.length && !pre
for (var d = 0; dropsEmpties && d < acc.length; d++) {
if (acc[d].length !== accBase[d]) {
dropsEmpties = false
}
}
values = []
var valuesLength = 0
outer: for (var j = 0; j < n.length; j++) {
var expanded = expand(n[j], max, maxLength, false)
for (var k = 0; k < expanded.length; k++) {
var v = expanded[k]
if (dropsEmpties && !v) continue
if (values.length >= max || valuesLength + v.length > maxLength) {
break outer
}
values.push(v)
valuesLength += v.length
} }
} }
} }
// at this point, n is the parts, and we know it's not a comma set nextBase = []
// with a single entry. acc = combine(
acc,
// no need to expand pre, since it is guaranteed to be free of brace-sets accBase,
var pre = m.pre; pre,
var post = m.post.length values,
? expand(m.post, max, false) max,
: ['']; maxLength,
dropEmpties && !m.post.length,
var N; nextBase
)
if (isSequence) { accBase = nextBase
var x = numeric(n[0]); if (!m.post.length) break
var y = numeric(n[1]); str = m.post
var width = Math.max(n[0].length, n[1].length)
var incr = n.length == 3
? Math.max(Math.abs(numeric(n[2])), 1)
: 1;
var test = lte;
var reverse = y < x;
if (reverse) {
incr *= -1;
test = gte;
}
var pad = n.some(isPadded);
N = [];
for (var i = x; test(i, y) && N.length < max; i += incr) {
var c;
if (isAlphaSequence) {
c = String.fromCharCode(i);
if (c === '\\')
c = '';
} else {
c = String(i);
if (pad) {
var need = width - c.length;
if (need > 0) {
var z = new Array(need + 1).join('0');
if (i < 0)
c = '-' + z + c.slice(1);
else
c = z + c;
}
}
}
N.push(c);
}
} else {
N = concatMap(n, function(el) { return expand(el, max, false) });
} }
for (var j = 0; j < N.length; j++) { return acc
for (var k = 0; k < post.length && expansions.length < max; k++) {
var expansion = pre + N[j] + post[k];
if (!isTop || isSequence || expansion)
expansions.push(expansion);
}
}
return expansions;
}
} }
@@ -14204,7 +14377,13 @@ function processHeader (request, key, val) {
} else if (typeof val[i] === 'object') { } else if (typeof val[i] === 'object') {
throw new InvalidArgumentError(`invalid ${key} header`) throw new InvalidArgumentError(`invalid ${key} header`)
} else { } else {
arr.push(`${val[i]}`) // Coerce primitives (and reject unsafe coercions such as functions
// with a crafted toString/Symbol.toPrimitive).
const str = `${val[i]}`
if (!isValidHeaderValue(str)) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
arr.push(str)
} }
} }
val = arr val = arr
@@ -14215,7 +14394,12 @@ function processHeader (request, key, val) {
} else if (val === null) { } else if (val === null) {
val = '' val = ''
} else { } else {
// Coerce primitives (and reject unsafe coercions such as functions
// with a crafted toString/Symbol.toPrimitive).
val = `${val}` val = `${val}`
if (!isValidHeaderValue(val)) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
} }
if (headerName === 'host') { if (headerName === 'host') {
@@ -15587,6 +15771,7 @@ const {
RequestContentLengthMismatchError, RequestContentLengthMismatchError,
ResponseContentLengthMismatchError, ResponseContentLengthMismatchError,
RequestAbortedError, RequestAbortedError,
InvalidArgumentError,
HeadersTimeoutError, HeadersTimeoutError,
HeadersOverflowError, HeadersOverflowError,
SocketError, SocketError,
@@ -16570,8 +16755,16 @@ function writeH1 (client, request) {
} }
body = bodyStream.stream body = bodyStream.stream
contentLength = bodyStream.length contentLength = bodyStream.length
} else if (util.isBlobLike(body) && request.contentType == null && body.type) { } else if (util.isBlobLike(body) && request.contentType == null) {
headers.push('content-type', body.type) const contentType = body.type
if (contentType) {
const contentTypeValue = `${contentType}`
if (!util.isValidHeaderValue(contentTypeValue)) {
util.errorRequest(client, request, new InvalidArgumentError('invalid content-type header'))
return false
}
headers.push('content-type', contentTypeValue)
}
} }
if (body && typeof body.read === 'function') { if (body && typeof body.read === 'function') {
@@ -20044,6 +20237,28 @@ function calculateRetryAfterHeader (retryAfter) {
return new Date(retryAfter).getTime() - current return new Date(retryAfter).getTime() - current
} }
function validatePartialResponseContentLength (headers, range, statusCode, retryCount) {
const contentLength = headers['content-length']
if (contentLength == null) {
return null
}
if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) {
return null
}
const length = Number(contentLength)
const expectedLength = range.end - range.start + 1
if (!Number.isFinite(length) || length !== expectedLength) {
return new RequestRetryError('Content-Length mismatch', statusCode, {
headers,
data: { count: retryCount }
})
}
return null
}
class RetryHandler { class RetryHandler {
constructor (opts, handlers) { constructor (opts, handlers) {
const { retryOptions, ...dispatchOpts } = opts const { retryOptions, ...dispatchOpts } = opts
@@ -20258,6 +20473,12 @@ class RetryHandler {
return false return false
} }
const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount)
if (contentLengthError != null) {
this.abort(contentLengthError)
return false
}
const { start, size, end = size - 1 } = contentRange const { start, size, end = size - 1 } = contentRange
assert(this.start === start, 'content-range mismatch') assert(this.start === start, 'content-range mismatch')
@@ -20281,6 +20502,12 @@ class RetryHandler {
) )
} }
const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount)
if (contentLengthError != null) {
this.abort(contentLengthError)
return false
}
const { start, size, end = size - 1 } = range const { start, size, end = size - 1 } = range
assert( assert(
start != null && Number.isFinite(start), start != null && Number.isFinite(start),
@@ -24525,7 +24752,7 @@ function validateCookiePath (path) {
if ( if (
code < 0x20 || // exclude CTLs (0-31) code < 0x20 || // exclude CTLs (0-31)
code === 0x7F || // DEL code > 0x7E || // exclude DEL and non-ascii
code === 0x3B // ; code === 0x3B // ;
) { ) {
throw new Error('Invalid cookie path') throw new Error('Invalid cookie path')
@@ -24534,16 +24761,80 @@ function validateCookiePath (path) {
} }
/** /**
* I have no idea why these values aren't allowed to be honest, * <let-dig> ::= <letter> | <digit>
* but Deno tests these. - Khafra *
* <letter> ::= any one of the 52 alphabetic characters A through Z in
* upper case and a through z in lower case
*
* <digit> ::= any one of the ten digits 0 through 9r
*
* @see https://www.rfc-editor.org/rfc/rfc1034#section-3.5
* @param {number} code
*/
function isLetterOrDigit (code) {
return (
(code >= 0x30 && code <= 0x39) || // 0-9
(code >= 0x41 && code <= 0x5A) || // A-Z
(code >= 0x61 && code <= 0x7A) // a-z
)
}
/**
* Validates a cookie domain against the "preferred name syntax".
*
* <domain> ::= <subdomain> | " "
* <subdomain> ::= <label> | <subdomain> "." <label>
* <label> ::= <let-dig> [ [ <ldh-str> ] <let-dig> ]
* <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
* <let-dig-hyp> ::= <let-dig> | "-"
*
* @see https://www.rfc-editor.org/rfc/rfc1034#section-3.5
* @see https://www.rfc-editor.org/rfc/rfc1123#section-2.1
* @see https://www.rfc-editor.org/rfc/rfc1035#section-2.3.4
* @param {string} domain * @param {string} domain
*/ */
function validateCookieDomain (domain) { function validateCookieDomain (domain) {
if ( // <domain> ::= <subdomain> | " "
domain.startsWith('-') || if (domain === ' ') {
domain.endsWith('.') || return
domain.endsWith('-') }
) {
if (domain.length > 255) {
throw new Error('Invalid cookie domain')
}
let labelLength = 0
for (let i = 0; i < domain.length; ++i) {
const code = domain.charCodeAt(i)
if (code === 0x2E) {
if (labelLength === 0) {
throw new Error('Invalid cookie domain')
}
if (domain.charCodeAt(i - 1) === 0x2D) { // "-"
throw new Error('Invalid cookie domain')
}
labelLength = 0
continue
}
if (labelLength === 0 && !isLetterOrDigit(code)) {
throw new Error('Invalid cookie domain')
}
if (!isLetterOrDigit(code) && code !== 0x2D) { // "-"
throw new Error('Invalid cookie domain')
}
if (++labelLength > 63) {
throw new Error('Invalid cookie domain')
}
}
if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 0x2D) { // "-"
throw new Error('Invalid cookie domain') throw new Error('Invalid cookie domain')
} }
} }
@@ -24686,7 +24977,13 @@ function stringify (cookie) {
const [key, ...value] = part.split('=') const [key, ...value] = part.split('=')
out.push(`${key.trim()}=${value.join('=')}`) const trimmedKey = key.trim()
const joinedValue = value.join('=')
validateCookieName(trimmedKey)
validateCookieValue(joinedValue)
out.push(`${trimmedKey}=${joinedValue}`)
} }
return out.join('; ') return out.join('; ')
+420 -97
View File
@@ -84,6 +84,20 @@ var escClose = '\0CLOSE'+Math.random()+'\0';
var escComma = '\0COMMA'+Math.random()+'\0'; var escComma = '\0COMMA'+Math.random()+'\0';
var escPeriod = '\0PERIOD'+Math.random()+'\0'; var escPeriod = '\0PERIOD'+Math.random()+'\0';
var EXPANSION_MAX = 100000
// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An
// input like `'{a,b}'.repeat(1500)` stays under that count - its output is
// truncated to 100k results - while making every result ~1500 characters
// long. The result set, and the intermediate arrays built while combining
// brace sets, then grow large enough to exhaust memory and crash the process
// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of
// characters the accumulator may hold at any point, so memory stays flat no
// matter how many brace groups are chained. The limit sits well above any
// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
// characters) so legitimate input is unaffected.
var EXPANSION_MAX_LENGTH = 4000000
function numeric(str) { function numeric(str) {
return parseInt(str, 10) == str return parseInt(str, 10) == str
? parseInt(str, 10) ? parseInt(str, 10)
@@ -142,7 +156,8 @@ function expandTop(str, options) {
return []; return [];
options = options || {}; options = options || {};
var max = options.max == null ? Infinity : options.max; var max = options.max == null ? EXPANSION_MAX : options.max;
var maxLength = options.maxLength == null ? EXPANSION_MAX_LENGTH : options.maxLength;
// I don't know why Bash 4.3 does this, but it does. // I don't know why Bash 4.3 does this, but it does.
// Anything starting with {} will have the first two bytes preserved // Anything starting with {} will have the first two bytes preserved
@@ -154,7 +169,7 @@ function expandTop(str, options) {
str = '\\{\\}' + str.substr(2); str = '\\{\\}' + str.substr(2);
} }
return expand(escapeBraces(str), max, true).map(unescapeBraces); return expand(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
} }
function identity(e) { function identity(e) {
@@ -175,15 +190,155 @@ function gte(i, y) {
return i >= y; return i >= y;
} }
function expand(str, max, isTop) { // Build `{ acc[a] + pre + values[v] }` for every combination, capping the
var expansions = []; // number of results at `max` and the total number of characters at `maxLength`.
// This is the one place output grows, so bounding it here keeps the single
// accumulator - and therefore memory - flat regardless of how many brace groups
// are combined (CVE-2026-14257).
//
// `base[a]` is the length of the part of `acc[a]` that predates the current
// empty-drop baseline (see `expand`). The matching baselines for the results
// are appended to `outBase`, which the caller carries forward alongside them.
function combine(
acc,
base,
pre,
values,
max,
maxLength,
dropEmpties,
outBase
) {
var out = []
var length = 0
for (var a = 0; a < acc.length; a++) {
for (var v = 0; v < values.length; v++) {
if (out.length >= max) return out
var expansion = acc[a] + pre + values[v]
// Bash drops empty results at the top level. Skip them before they count
// against `max`, so `max` bounds the number of *kept* results. "Empty"
// means "adds nothing past the baseline", not "empty overall".
if (dropEmpties && expansion.length === base[a]) continue
if (length + expansion.length > maxLength) return out
out.push(expansion)
outBase.push(base[a])
length += expansion.length
}
}
return out
}
// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
// sequence body.
function expandSequence(
body,
isAlphaSequence,
max,
maxLength
) {
var n = body.split(/\.\./)
var N = []
// A sequence body always splits into two or three parts, but the compiler
// can't know that.
/* c8 ignore start */
if (n[0] === undefined || n[1] === undefined) {
return N
}
/* c8 ignore stop */
var x = numeric(n[0])
var y = numeric(n[1])
var width = Math.max(n[0].length, n[1].length)
var incr =
n.length === 3 && n[2] !== undefined ?
Math.max(Math.abs(numeric(n[2])), 1)
: 1
var test = lte
var reverse = y < x
if (reverse) {
incr *= -1
test = gte
}
var pad = n.some(isPadded)
var length = 0
for (var i = x; test(i, y) && N.length < max; i += incr) {
var c
if (isAlphaSequence) {
c = String.fromCharCode(i)
if (c === '\\') {
c = ''
}
} else {
c = String(i)
if (pad) {
var need = width - c.length
if (need > 0) {
var z = new Array(need + 1).join('0')
if (i < 0) {
c = '-' + z + c.slice(1)
} else {
c = z + c
}
}
}
}
if (length + c.length > maxLength) break
N.push(c)
length += c.length
}
return N
}
function expand(
str,
max,
maxLength,
isTop
) {
// Consume the string's top-level brace groups left to right, threading a
// running set of combined prefixes (`acc`). Expanding the tail iteratively -
// rather than recursing on `m.post` once per group - keeps the native stack
// depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no
// longer overflow the stack, and leaves a single accumulator whose size
// `maxLength` bounds directly (CVE-2026-14257).
var acc = ['']
// Bash drops empty results, but only when the *first* group of the run is a
// comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
// is on the final strings, so it is applied to whichever `combine` produces
// them (the one with no brace set left in the tail).
//
// The old implementation recursed on `m.post`, so the drop tested only the
// expansion of the current call's substring. The `{a},b}` rewrite below turns
// `isTop` back on part-way through a string, starting a fresh such run, so
// the drop must ignore whatever `acc` already holds from earlier groups.
// `accBase[a]` records how much of `acc[a]` predates the current run;
// `combine` treats an expansion as empty when it adds nothing past that.
var accBase = [0]
var dropEmpties = false
var firstGroup = true
var nextBase
// The `{a},b}` rewrite below restarts expansion on a rewritten string with
// the same `max` and `isTop = true`. Loop instead of recursing so a long run
// of non-expanding `{}` groups can't exhaust the call stack.
for (;;) { for (;;) {
var m = balanced('{', '}', str); var m = balanced('{', '}', str);
if (!m || /\$$/.test(m.pre)) return [str];
// No brace set left: the rest of the string is literal.
if (!m) {
return combine(acc, accBase, str, [''], max, maxLength, dropEmpties, [])
}
// no need to expand pre, since it is guaranteed to be free of brace-sets
var pre = m.pre;
// For compatibility reasons, `${` is not eligible for brace expansion, and
// on the 1.x line it suppresses expansion of the rest of the string too:
// the whole remainder is literal. The 2.x and 5.x lines instead keep
// expanding the tail, which is what bash does, but changing that here would
// be a breaking change for 1.x consumers. Routed through `combine` so the
// result is still bounded by `max` and `maxLength`.
if (/\$$/.test(pre)) {
return combine(acc, accBase, str, [''], max, maxLength, dropEmpties, [])
}
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
@@ -193,94 +348,112 @@ function expand(str, max, isTop) {
// {a},b} // {a},b}
if (m.post.match(/,(?!,).*\}/)) { if (m.post.match(/,(?!,).*\}/)) {
str = m.pre + '{' + m.body + escClose + m.post; str = m.pre + '{' + m.body + escClose + m.post;
// The rewritten string is expanded as if it were a fresh top-level one,
// so start a new empty-drop run: anchor the baseline at what `acc`
// holds now, and let the next expanding group decide whether to drop.
isTop = true isTop = true
firstGroup = true
dropEmpties = false
accBase = []
for (var b = 0; b < acc.length; b++) {
accBase.push(acc[b].length)
}
continue continue
} }
return [str]; // Nothing here expands, so the whole remaining string is literal.
return combine(
acc,
accBase,
pre + '{' + m.body + '}' + m.post,
[''],
max,
maxLength,
dropEmpties,
[]
)
} }
var n; if (firstGroup) {
dropEmpties = isTop && !isSequence
firstGroup = false
}
var values;
if (isSequence) { if (isSequence) {
n = m.body.split(/\.\./); values = expandSequence(m.body, isAlphaSequence, max, maxLength);
} else { } else {
n = parseCommaParts(m.body); var n = parseCommaParts(m.body);
if (n.length === 1) { if (n.length === 1 && n[0] !== undefined) {
// x{{a,b}}y ==> x{a}y x{b}y // x{{a,b}}y ==> x{a}y x{b}y
n = expand(n[0], max, false).map(embrace); n = expand(n[0], max, maxLength, false).map(embrace);
//XXX is this necessary? Can't seem to hit it in tests.
/* c8 ignore start */
if (n.length === 1) { if (n.length === 1) {
var post = m.post.length nextBase = []
? expand(m.post, max, false) acc = combine(
: ['']; acc,
return post.map(function(p) { accBase,
return m.pre + n[0] + p; pre + n[0],
}); [''],
max,
maxLength,
dropEmpties && !m.post.length,
nextBase
)
accBase = nextBase
if (!m.post.length) break
str = m.post
continue
}
/* c8 ignore stop */
}
// Values that `combine` is going to drop as empty produce no result, so
// they must not count against `max` - otherwise `{a,,b}` with `max: 2`
// would stop at `['a', '']` and yield one result instead of two. Skipping
// them outright keeps `values` bounded while leaving `max` a bound on
// *kept* results. A value is dropped when it adds nothing past the
// baseline, which is what `combine` tests.
var dropsEmpties = dropEmpties && !m.post.length && !pre
for (var d = 0; dropsEmpties && d < acc.length; d++) {
if (acc[d].length !== accBase[d]) {
dropsEmpties = false
}
}
values = []
var valuesLength = 0
outer: for (var j = 0; j < n.length; j++) {
var expanded = expand(n[j], max, maxLength, false)
for (var k = 0; k < expanded.length; k++) {
var v = expanded[k]
if (dropsEmpties && !v) continue
if (values.length >= max || valuesLength + v.length > maxLength) {
break outer
}
values.push(v)
valuesLength += v.length
} }
} }
} }
// at this point, n is the parts, and we know it's not a comma set nextBase = []
// with a single entry. acc = combine(
acc,
// no need to expand pre, since it is guaranteed to be free of brace-sets accBase,
var pre = m.pre; pre,
var post = m.post.length values,
? expand(m.post, max, false) max,
: ['']; maxLength,
dropEmpties && !m.post.length,
var N; nextBase
)
if (isSequence) { accBase = nextBase
var x = numeric(n[0]); if (!m.post.length) break
var y = numeric(n[1]); str = m.post
var width = Math.max(n[0].length, n[1].length)
var incr = n.length == 3
? Math.max(Math.abs(numeric(n[2])), 1)
: 1;
var test = lte;
var reverse = y < x;
if (reverse) {
incr *= -1;
test = gte;
}
var pad = n.some(isPadded);
N = [];
for (var i = x; test(i, y) && N.length < max; i += incr) {
var c;
if (isAlphaSequence) {
c = String.fromCharCode(i);
if (c === '\\')
c = '';
} else {
c = String(i);
if (pad) {
var need = width - c.length;
if (need > 0) {
var z = new Array(need + 1).join('0');
if (i < 0)
c = '-' + z + c.slice(1);
else
c = z + c;
}
}
}
N.push(c);
}
} else {
N = concatMap(n, function(el) { return expand(el, max, false) });
} }
for (var j = 0; j < N.length; j++) { return acc
for (var k = 0; k < post.length && expansions.length < max; k++) {
var expansion = pre + N[j] + post[k];
if (!isTop || isSequence || expansion)
expansions.push(expansion);
}
}
return expansions;
}
} }
@@ -14204,7 +14377,13 @@ function processHeader (request, key, val) {
} else if (typeof val[i] === 'object') { } else if (typeof val[i] === 'object') {
throw new InvalidArgumentError(`invalid ${key} header`) throw new InvalidArgumentError(`invalid ${key} header`)
} else { } else {
arr.push(`${val[i]}`) // Coerce primitives (and reject unsafe coercions such as functions
// with a crafted toString/Symbol.toPrimitive).
const str = `${val[i]}`
if (!isValidHeaderValue(str)) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
arr.push(str)
} }
} }
val = arr val = arr
@@ -14215,7 +14394,12 @@ function processHeader (request, key, val) {
} else if (val === null) { } else if (val === null) {
val = '' val = ''
} else { } else {
// Coerce primitives (and reject unsafe coercions such as functions
// with a crafted toString/Symbol.toPrimitive).
val = `${val}` val = `${val}`
if (!isValidHeaderValue(val)) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
} }
if (headerName === 'host') { if (headerName === 'host') {
@@ -15587,6 +15771,7 @@ const {
RequestContentLengthMismatchError, RequestContentLengthMismatchError,
ResponseContentLengthMismatchError, ResponseContentLengthMismatchError,
RequestAbortedError, RequestAbortedError,
InvalidArgumentError,
HeadersTimeoutError, HeadersTimeoutError,
HeadersOverflowError, HeadersOverflowError,
SocketError, SocketError,
@@ -16570,8 +16755,16 @@ function writeH1 (client, request) {
} }
body = bodyStream.stream body = bodyStream.stream
contentLength = bodyStream.length contentLength = bodyStream.length
} else if (util.isBlobLike(body) && request.contentType == null && body.type) { } else if (util.isBlobLike(body) && request.contentType == null) {
headers.push('content-type', body.type) const contentType = body.type
if (contentType) {
const contentTypeValue = `${contentType}`
if (!util.isValidHeaderValue(contentTypeValue)) {
util.errorRequest(client, request, new InvalidArgumentError('invalid content-type header'))
return false
}
headers.push('content-type', contentTypeValue)
}
} }
if (body && typeof body.read === 'function') { if (body && typeof body.read === 'function') {
@@ -20044,6 +20237,28 @@ function calculateRetryAfterHeader (retryAfter) {
return new Date(retryAfter).getTime() - current return new Date(retryAfter).getTime() - current
} }
function validatePartialResponseContentLength (headers, range, statusCode, retryCount) {
const contentLength = headers['content-length']
if (contentLength == null) {
return null
}
if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) {
return null
}
const length = Number(contentLength)
const expectedLength = range.end - range.start + 1
if (!Number.isFinite(length) || length !== expectedLength) {
return new RequestRetryError('Content-Length mismatch', statusCode, {
headers,
data: { count: retryCount }
})
}
return null
}
class RetryHandler { class RetryHandler {
constructor (opts, handlers) { constructor (opts, handlers) {
const { retryOptions, ...dispatchOpts } = opts const { retryOptions, ...dispatchOpts } = opts
@@ -20258,6 +20473,12 @@ class RetryHandler {
return false return false
} }
const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount)
if (contentLengthError != null) {
this.abort(contentLengthError)
return false
}
const { start, size, end = size - 1 } = contentRange const { start, size, end = size - 1 } = contentRange
assert(this.start === start, 'content-range mismatch') assert(this.start === start, 'content-range mismatch')
@@ -20281,6 +20502,12 @@ class RetryHandler {
) )
} }
const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount)
if (contentLengthError != null) {
this.abort(contentLengthError)
return false
}
const { start, size, end = size - 1 } = range const { start, size, end = size - 1 } = range
assert( assert(
start != null && Number.isFinite(start), start != null && Number.isFinite(start),
@@ -24525,7 +24752,7 @@ function validateCookiePath (path) {
if ( if (
code < 0x20 || // exclude CTLs (0-31) code < 0x20 || // exclude CTLs (0-31)
code === 0x7F || // DEL code > 0x7E || // exclude DEL and non-ascii
code === 0x3B // ; code === 0x3B // ;
) { ) {
throw new Error('Invalid cookie path') throw new Error('Invalid cookie path')
@@ -24534,16 +24761,80 @@ function validateCookiePath (path) {
} }
/** /**
* I have no idea why these values aren't allowed to be honest, * <let-dig> ::= <letter> | <digit>
* but Deno tests these. - Khafra *
* <letter> ::= any one of the 52 alphabetic characters A through Z in
* upper case and a through z in lower case
*
* <digit> ::= any one of the ten digits 0 through 9r
*
* @see https://www.rfc-editor.org/rfc/rfc1034#section-3.5
* @param {number} code
*/
function isLetterOrDigit (code) {
return (
(code >= 0x30 && code <= 0x39) || // 0-9
(code >= 0x41 && code <= 0x5A) || // A-Z
(code >= 0x61 && code <= 0x7A) // a-z
)
}
/**
* Validates a cookie domain against the "preferred name syntax".
*
* <domain> ::= <subdomain> | " "
* <subdomain> ::= <label> | <subdomain> "." <label>
* <label> ::= <let-dig> [ [ <ldh-str> ] <let-dig> ]
* <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
* <let-dig-hyp> ::= <let-dig> | "-"
*
* @see https://www.rfc-editor.org/rfc/rfc1034#section-3.5
* @see https://www.rfc-editor.org/rfc/rfc1123#section-2.1
* @see https://www.rfc-editor.org/rfc/rfc1035#section-2.3.4
* @param {string} domain * @param {string} domain
*/ */
function validateCookieDomain (domain) { function validateCookieDomain (domain) {
if ( // <domain> ::= <subdomain> | " "
domain.startsWith('-') || if (domain === ' ') {
domain.endsWith('.') || return
domain.endsWith('-') }
) {
if (domain.length > 255) {
throw new Error('Invalid cookie domain')
}
let labelLength = 0
for (let i = 0; i < domain.length; ++i) {
const code = domain.charCodeAt(i)
if (code === 0x2E) {
if (labelLength === 0) {
throw new Error('Invalid cookie domain')
}
if (domain.charCodeAt(i - 1) === 0x2D) { // "-"
throw new Error('Invalid cookie domain')
}
labelLength = 0
continue
}
if (labelLength === 0 && !isLetterOrDigit(code)) {
throw new Error('Invalid cookie domain')
}
if (!isLetterOrDigit(code) && code !== 0x2D) { // "-"
throw new Error('Invalid cookie domain')
}
if (++labelLength > 63) {
throw new Error('Invalid cookie domain')
}
}
if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 0x2D) { // "-"
throw new Error('Invalid cookie domain') throw new Error('Invalid cookie domain')
} }
} }
@@ -24686,7 +24977,13 @@ function stringify (cookie) {
const [key, ...value] = part.split('=') const [key, ...value] = part.split('=')
out.push(`${key.trim()}=${value.join('=')}`) const trimmedKey = key.trim()
const joinedValue = value.join('=')
validateCookieName(trimmedKey)
validateCookieValue(joinedValue)
out.push(`${trimmedKey}=${joinedValue}`)
} }
return out.join('; ') return out.join('; ')
@@ -97137,7 +97434,7 @@ function combine(acc, pre, values, max, maxLength, dropEmpties) {
} }
// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`) // The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
// sequence body. // sequence body.
function expandSequence(body, isAlphaSequence, max) { function expandSequence(body, isAlphaSequence, max, maxLength) {
const n = body.split(/\.\./); const n = body.split(/\.\./);
const N = []; const N = [];
// A sequence body always splits into two or three parts, but the compiler // A sequence body always splits into two or three parts, but the compiler
@@ -97160,6 +97457,7 @@ function expandSequence(body, isAlphaSequence, max) {
test = gte; test = gte;
} }
const pad = n.some(isPadded); const pad = n.some(isPadded);
let length = 0;
for (let i = x; test(i, y) && N.length < max; i += incr) { for (let i = x; test(i, y) && N.length < max; i += incr) {
let c; let c;
if (isAlphaSequence) { if (isAlphaSequence) {
@@ -97183,7 +97481,10 @@ function expandSequence(body, isAlphaSequence, max) {
} }
} }
} }
if (length + c.length > maxLength)
break;
N.push(c); N.push(c);
length += c.length;
} }
return N; return N;
} }
@@ -97237,7 +97538,7 @@ function expand_(str, max, maxLength, isTop) {
} }
let values; let values;
if (isSequence) { if (isSequence) {
values = expandSequence(m.body, isAlphaSequence, max); values = expandSequence(m.body, isAlphaSequence, max, maxLength);
} }
else { else {
let n = parseCommaParts(m.body); let n = parseCommaParts(m.body);
@@ -97255,9 +97556,31 @@ function expand_(str, max, maxLength, isTop) {
} }
/* c8 ignore stop */ /* c8 ignore stop */
} }
// Values that `combine` is going to drop as empty produce no result, so
// they must not count against `max` - otherwise `{a,,b}` with `max: 2`
// would stop at `['a', '']` and yield one result instead of two. Skipping
// them outright keeps `values` bounded while leaving `max` a bound on
// *kept* results.
let dropsEmpties = dropEmpties && !m.post.length && !pre;
for (let d = 0; dropsEmpties && d < acc.length; d++) {
if (acc[d]) {
dropsEmpties = false;
}
}
values = []; values = [];
for (let j = 0; j < n.length; j++) { let valuesLength = 0;
values.push.apply(values, expand_(n[j], max, maxLength, false)); outer: for (let j = 0; j < n.length; j++) {
const expanded = expand_(n[j], max, maxLength, false);
for (let k = 0; k < expanded.length; k++) {
const v = expanded[k];
if (dropsEmpties && !v)
continue;
if (values.length >= max || valuesLength + v.length > maxLength) {
break outer;
}
values.push(v);
valuesLength += v.length;
}
} }
} }
acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length); acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length);
+22 -22
View File
@@ -32,7 +32,7 @@
"eslint-plugin-n": "^18.1.0", "eslint-plugin-n": "^18.1.0",
"globals": "^17.7.0", "globals": "^17.7.0",
"jest": "^30.4.2", "jest": "^30.4.2",
"nock": "^14.0.17", "nock": "^14.0.0",
"prettier": "^3.8.4", "prettier": "^3.8.4",
"ts-jest": "^29.4.11", "ts-jest": "^29.4.11",
"typescript": "^6.0.3" "typescript": "^6.0.3"
@@ -75,9 +75,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@actions/cache/node_modules/brace-expansion": { "node_modules/@actions/cache/node_modules/brace-expansion": {
"version": "1.1.16", "version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
@@ -2716,9 +2716,9 @@
} }
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "5.0.8", "version": "5.0.9",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"balanced-match": "^4.0.2" "balanced-match": "^4.0.2"
@@ -3874,9 +3874,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/glob/node_modules/brace-expansion": { "node_modules/glob/node_modules/brace-expansion": {
"version": "2.1.2", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
"integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -4824,9 +4824,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "3.15.0", "version": "3.15.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz",
"integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -5094,9 +5094,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/nock": { "node_modules/nock": {
"version": "14.0.17", "version": "14.0.15",
"resolved": "https://registry.npmjs.org/nock/-/nock-14.0.17.tgz", "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.15.tgz",
"integrity": "sha512-EjRr1weMa4ALQX35AgZTEnP+weJJjlW1KGDiNM2IQC2069YDHas4f4B4UUYR+TTLyKWxJvOz2wObDKQs/LNreA==", "integrity": "sha512-S0a47C9pLvcYx/Ugf0H30BVBEcUgMMBDk9VJIDlJ8XGrfH2QDUD4Tgdp45qDIiHttokBG+IbsOtsvIjGR/j3bg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -5957,9 +5957,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/test-exclude/node_modules/brace-expansion": { "node_modules/test-exclude/node_modules/brace-expansion": {
"version": "1.1.16", "version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -6185,9 +6185,9 @@
} }
}, },
"node_modules/undici": { "node_modules/undici": {
"version": "6.27.0", "version": "6.28.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
"integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=18.17" "node": ">=18.17"
+1 -1
View File
@@ -52,7 +52,7 @@
"eslint-plugin-n": "^18.1.0", "eslint-plugin-n": "^18.1.0",
"globals": "^17.7.0", "globals": "^17.7.0",
"jest": "^30.4.2", "jest": "^30.4.2",
"nock": "^14.0.17", "nock": "^14.0.0",
"prettier": "^3.8.4", "prettier": "^3.8.4",
"ts-jest": "^29.4.11", "ts-jest": "^29.4.11",
"typescript": "^6.0.3" "typescript": "^6.0.3"