Skip to content

Commit b24925b

Browse files
dependabot[bot]brunoborgesCopilot
authored
chore(deps): bump undici from 6.28.0 to 6.29.0 (#1274)
* chore(deps): bump undici from 6.28.0 to 6.29.0 Bumps [undici](https://github.com/nodejs/undici) from 6.28.0 to 6.29.0. - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](nodejs/undici@v6.28.0...v6.29.0) --- updated-dependencies: - dependency-name: undici dependency-version: 6.29.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> * chore(deps): update generated undici artifacts Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * chore(deps): bump brace-expansion to 5.0.12 to fix high-severity audit Resolves GHSA-q2hr-2g5m-vwhr, GHSA-qhr7-859c-m2p7, GHSA-6j4f-fj2g-mc7p. Regenerates dist/ and updates licensed cache. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bruno Borges <brborges@microsoft.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 47b3648 commit b24925b

7 files changed

Lines changed: 1052 additions & 432 deletions

File tree

‎.licenses/npm/brace-expansion.dep.yml‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎.licenses/npm/undici.dep.yml‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/cleanup/767.index.js‎

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -59498,6 +59498,24 @@ const EXPANSION_MAX = 100_000;
5949859498
// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
5949959499
// characters) so legitimate input is unaffected.
5950059500
const EXPANSION_MAX_LENGTH = 4_000_000;
59501+
// `expand_` recurses once per level of brace *nesting* - both when expanding a
59502+
// set's comma members and when re-wrapping a set whose body is a single part.
59503+
// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one
59504+
// level per chained group), which left nesting depth unbounded: about 3,100
59505+
// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack
59506+
// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser
59507+
// will follow nesting. It sits far above any realistic pattern and well below
59508+
// the depth at which the stack runs out.
59509+
const EXPANSION_MAX_DEPTH = 1_000;
59510+
// Bash keeps a quirk where a brace group followed by a comma set still expands
59511+
// (`{a},b}`). The parser implements it by rewriting the string and restarting
59512+
// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`
59513+
// full passes over a string that itself grows by one `escClose` sentinel each
59514+
// time - quadratic in `n`, with a ~26x constant from the sentinel's length.
59515+
// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27
59516+
// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many
59517+
// times the scan may restart. Real `{a},b}` input needs a handful.
59518+
const EXPANSION_MAX_REWRITES = 1_000;
5950159519
function numeric(str) {
5950259520
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
5950359521
}
@@ -59517,37 +59535,52 @@ function unescapeBraces(str) {
5951759535
.replace(escCommaPattern, ',')
5951859536
.replace(escPeriodPattern, '.');
5951959537
}
59538+
// Like `target.push(...items)` but doesn't overflow the stack
59539+
function pushAll(target, items) {
59540+
for (let i = 0; i < items.length; i++) {
59541+
target.push(items[i]);
59542+
}
59543+
}
5952059544
/**
5952159545
* Basically just str.split(","), but handling cases
5952259546
* where we have nested braced sections, which should be
5952359547
* treated as individual members, like {a,{b,c},d}
5952459548
*/
5952559549
function parseCommaParts(str) {
59526-
if (!str) {
59527-
return [''];
59528-
}
5952959550
const parts = [];
59530-
const m = balanced('{', '}', str);
59531-
if (!m) {
59532-
return str.split(',');
59533-
}
59534-
const { pre, body, post } = m;
59535-
const p = pre.split(',');
59536-
p[p.length - 1] += '{' + body + '}';
59537-
const postParts = parseCommaParts(post);
59538-
if (post.length) {
59539-
;
59540-
p[p.length - 1] += postParts.shift();
59541-
p.push.apply(p, postParts);
59542-
}
59543-
parts.push.apply(parts, p);
59544-
return parts;
59551+
// Walk the brace groups iteratively. Recursing on `post` once per group let a
59552+
// chain of them exhaust the stack - the parsing-side counterpart to
59553+
// the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or
59554+
// `maxLength` can bound, since it happens before expansion.
59555+
//
59556+
// The part the next chunk continues
59557+
let carry = '';
59558+
for (;;) {
59559+
const m = balanced('{', '}', str);
59560+
if (!m) {
59561+
const tail = str.split(',');
59562+
tail[0] = carry + tail[0];
59563+
pushAll(parts, tail);
59564+
return parts;
59565+
}
59566+
const { pre, body, post } = m;
59567+
const p = pre.split(',');
59568+
p[0] = carry + p[0];
59569+
p[p.length - 1] += '{' + body + '}';
59570+
if (!post.length) {
59571+
pushAll(parts, p);
59572+
return parts;
59573+
}
59574+
carry = p.pop();
59575+
pushAll(parts, p);
59576+
str = post;
59577+
}
5954559578
}
5954659579
function expand(str, options = {}) {
5954759580
if (!str) {
5954859581
return [];
5954959582
}
59550-
const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH } = options;
59583+
const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH, maxDepth = EXPANSION_MAX_DEPTH, maxRewrites = EXPANSION_MAX_REWRITES, } = options;
5955159584
// I don't know why Bash 4.3 does this, but it does.
5955259585
// Anything starting with {} will have the first two bytes preserved
5955359586
// but *only* at the top level, so {},a}b will not expand to anything,
@@ -59557,7 +59590,7 @@ function expand(str, options = {}) {
5955759590
if (str.slice(0, 2) === '{}') {
5955859591
str = '\\{\\}' + str.slice(2);
5955959592
}
59560-
return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
59593+
return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces);
5956159594
}
5956259595
function embrace(str) {
5956359596
return '{' + str + '}';
@@ -59652,7 +59685,13 @@ function expandSequence(body, isAlphaSequence, max, maxLength) {
5965259685
}
5965359686
return N;
5965459687
}
59655-
function expand_(str, max, maxLength, isTop) {
59688+
function expand_(str, max, maxLength, maxDepth, depth, maxRewrites, isTop) {
59689+
// Too deeply nested to keep following: treat the rest as literal, the same
59690+
// way a group that cannot expand is already handled. Truncating rather than
59691+
// throwing keeps `expand` total, matching `max` and `maxLength`.
59692+
if (depth > maxDepth) {
59693+
return [str];
59694+
}
5965659695
// Consume the string's top-level brace groups left to right, threading a
5965759696
// running set of combined prefixes (`acc`). Expanding the tail iteratively -
5965859697
// rather than recursing on `m.post` once per group - keeps the native stack
@@ -59664,6 +59703,9 @@ function expand_(str, max, maxLength, isTop) {
5966459703
// comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
5966559704
// is on the final strings, so it is applied to whichever `combine` produces
5966659705
// them (the one with no brace set left in the tail).
59706+
// How many times the `{a},b}` rewrite below has restarted the scan. Each pass
59707+
// re-reads the whole string, so leaving this unbounded is quadratic.
59708+
let rewrites = 0;
5966759709
let dropEmpties = false;
5966859710
let firstGroup = true;
5966959711
for (;;) {
@@ -59688,7 +59730,8 @@ function expand_(str, max, maxLength, isTop) {
5968859730
const isOptions = m.body.indexOf(',') >= 0;
5968959731
if (!isSequence && !isOptions) {
5969059732
// {a},b}
59691-
if (m.post.match(/,(?!,).*\}/)) {
59733+
if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) {
59734+
rewrites++;
5969259735
str = m.pre + '{' + m.body + escClose + m.post;
5969359736
isTop = true;
5969459737
continue;
@@ -59708,7 +59751,7 @@ function expand_(str, max, maxLength, isTop) {
5970859751
let n = parseCommaParts(m.body);
5970959752
if (n.length === 1 && n[0] !== undefined) {
5971059753
// x{{a,b}}y ==> x{a}y x{b}y
59711-
n = expand_(n[0], max, maxLength, false).map(embrace);
59754+
n = expand_(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace);
5971259755
//XXX is this necessary? Can't seem to hit it in tests.
5971359756
/* c8 ignore start */
5971459757
if (n.length === 1) {
@@ -59734,12 +59777,13 @@ function expand_(str, max, maxLength, isTop) {
5973459777
values = [];
5973559778
let valuesLength = 0;
5973659779
outer: for (let j = 0; j < n.length; j++) {
59737-
const expanded = expand_(n[j], max, maxLength, false);
59780+
const expanded = expand_(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false);
5973859781
for (let k = 0; k < expanded.length; k++) {
5973959782
const v = expanded[k];
5974059783
if (dropsEmpties && !v)
5974159784
continue;
59742-
if (values.length >= max || valuesLength + v.length > maxLength) {
59785+
if (values.length >= max ||
59786+
valuesLength + v.length > maxLength) {
5974359787
break outer;
5974459788
}
5974559789
values.push(v);

0 commit comments

Comments
 (0)