Skip to content

Commit 0e40890

Browse files
Bump brace-expansion from 5.0.9 to 5.0.12 (#1365)
* Bump brace-expansion from 5.0.9 to 5.0.12 Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 5.0.9 to 5.0.12. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v5.0.9...v5.0.12) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 5.0.12 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> * Update License * Fix poetry issue --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: HarithaVattikuti <73516759+HarithaVattikuti@users.noreply.github.com>
1 parent 3892123 commit 0e40890

5 files changed

Lines changed: 212 additions & 80 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.

‎__tests__/data/pyproject.toml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ description = ""
55
authors = ["Your Name <you@example.com>"]
66

77
[tool.poetry.dependencies]
8-
python = ">=3.9,<3.14"
8+
python = ">=3.9,<3.15"
99
flake8 = "^4.0.1"
10-
pyinstaller = "6.10.0"
10+
pyinstaller = "6.16.0"
1111
setuptools = ">=78.1.1"
1212
packaging = ">=22.0,<26"
1313

‎dist/cache-save/index.js‎

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41344,7 +41344,7 @@ exports.range = range;
4134441344

4134541345

4134641346
Object.defineProperty(exports, "__esModule", ({ value: true }));
41347-
exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0;
41347+
exports.EXPANSION_MAX_REWRITES = exports.EXPANSION_MAX_DEPTH = exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0;
4134841348
exports.expand = expand;
4134941349
const balanced_match_1 = __nccwpck_require__(2649);
4135041350
const escSlash = '\0SLASH' + Math.random() + '\0';
@@ -41374,6 +41374,24 @@ exports.EXPANSION_MAX = 100_000;
4137441374
// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
4137541375
// characters) so legitimate input is unaffected.
4137641376
exports.EXPANSION_MAX_LENGTH = 4_000_000;
41377+
// `expand_` recurses once per level of brace *nesting* - both when expanding a
41378+
// set's comma members and when re-wrapping a set whose body is a single part.
41379+
// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one
41380+
// level per chained group), which left nesting depth unbounded: about 3,100
41381+
// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack
41382+
// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser
41383+
// will follow nesting. It sits far above any realistic pattern and well below
41384+
// the depth at which the stack runs out.
41385+
exports.EXPANSION_MAX_DEPTH = 1_000;
41386+
// Bash keeps a quirk where a brace group followed by a comma set still expands
41387+
// (`{a},b}`). The parser implements it by rewriting the string and restarting
41388+
// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`
41389+
// full passes over a string that itself grows by one `escClose` sentinel each
41390+
// time - quadratic in `n`, with a ~26x constant from the sentinel's length.
41391+
// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27
41392+
// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many
41393+
// times the scan may restart. Real `{a},b}` input needs a handful.
41394+
exports.EXPANSION_MAX_REWRITES = 1_000;
4137741395
function numeric(str) {
4137841396
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
4137941397
}
@@ -41393,37 +41411,52 @@ function unescapeBraces(str) {
4139341411
.replace(escCommaPattern, ',')
4139441412
.replace(escPeriodPattern, '.');
4139541413
}
41414+
// Like `target.push(...items)` but doesn't overflow the stack
41415+
function pushAll(target, items) {
41416+
for (let i = 0; i < items.length; i++) {
41417+
target.push(items[i]);
41418+
}
41419+
}
4139641420
/**
4139741421
* Basically just str.split(","), but handling cases
4139841422
* where we have nested braced sections, which should be
4139941423
* treated as individual members, like {a,{b,c},d}
4140041424
*/
4140141425
function parseCommaParts(str) {
41402-
if (!str) {
41403-
return [''];
41404-
}
4140541426
const parts = [];
41406-
const m = (0, balanced_match_1.balanced)('{', '}', str);
41407-
if (!m) {
41408-
return str.split(',');
41409-
}
41410-
const { pre, body, post } = m;
41411-
const p = pre.split(',');
41412-
p[p.length - 1] += '{' + body + '}';
41413-
const postParts = parseCommaParts(post);
41414-
if (post.length) {
41415-
;
41416-
p[p.length - 1] += postParts.shift();
41417-
p.push.apply(p, postParts);
41427+
// Walk the brace groups iteratively. Recursing on `post` once per group let a
41428+
// chain of them exhaust the stack - the parsing-side counterpart to
41429+
// the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or
41430+
// `maxLength` can bound, since it happens before expansion.
41431+
//
41432+
// The part the next chunk continues
41433+
let carry = '';
41434+
for (;;) {
41435+
const m = (0, balanced_match_1.balanced)('{', '}', str);
41436+
if (!m) {
41437+
const tail = str.split(',');
41438+
tail[0] = carry + tail[0];
41439+
pushAll(parts, tail);
41440+
return parts;
41441+
}
41442+
const { pre, body, post } = m;
41443+
const p = pre.split(',');
41444+
p[0] = carry + p[0];
41445+
p[p.length - 1] += '{' + body + '}';
41446+
if (!post.length) {
41447+
pushAll(parts, p);
41448+
return parts;
41449+
}
41450+
carry = p.pop();
41451+
pushAll(parts, p);
41452+
str = post;
4141841453
}
41419-
parts.push.apply(parts, p);
41420-
return parts;
4142141454
}
4142241455
function expand(str, options = {}) {
4142341456
if (!str) {
4142441457
return [];
4142541458
}
41426-
const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH } = options;
41459+
const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH, maxDepth = exports.EXPANSION_MAX_DEPTH, maxRewrites = exports.EXPANSION_MAX_REWRITES, } = options;
4142741460
// I don't know why Bash 4.3 does this, but it does.
4142841461
// Anything starting with {} will have the first two bytes preserved
4142941462
// but *only* at the top level, so {},a}b will not expand to anything,
@@ -41433,7 +41466,7 @@ function expand(str, options = {}) {
4143341466
if (str.slice(0, 2) === '{}') {
4143441467
str = '\\{\\}' + str.slice(2);
4143541468
}
41436-
return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
41469+
return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces);
4143741470
}
4143841471
function embrace(str) {
4143941472
return '{' + str + '}';
@@ -41528,7 +41561,13 @@ function expandSequence(body, isAlphaSequence, max, maxLength) {
4152841561
}
4152941562
return N;
4153041563
}
41531-
function expand_(str, max, maxLength, isTop) {
41564+
function expand_(str, max, maxLength, maxDepth, depth, maxRewrites, isTop) {
41565+
// Too deeply nested to keep following: treat the rest as literal, the same
41566+
// way a group that cannot expand is already handled. Truncating rather than
41567+
// throwing keeps `expand` total, matching `max` and `maxLength`.
41568+
if (depth > maxDepth) {
41569+
return [str];
41570+
}
4153241571
// Consume the string's top-level brace groups left to right, threading a
4153341572
// running set of combined prefixes (`acc`). Expanding the tail iteratively -
4153441573
// rather than recursing on `m.post` once per group - keeps the native stack
@@ -41540,6 +41579,9 @@ function expand_(str, max, maxLength, isTop) {
4154041579
// comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
4154141580
// is on the final strings, so it is applied to whichever `combine` produces
4154241581
// them (the one with no brace set left in the tail).
41582+
// How many times the `{a},b}` rewrite below has restarted the scan. Each pass
41583+
// re-reads the whole string, so leaving this unbounded is quadratic.
41584+
let rewrites = 0;
4154341585
let dropEmpties = false;
4154441586
let firstGroup = true;
4154541587
for (;;) {
@@ -41564,7 +41606,8 @@ function expand_(str, max, maxLength, isTop) {
4156441606
const isOptions = m.body.indexOf(',') >= 0;
4156541607
if (!isSequence && !isOptions) {
4156641608
// {a},b}
41567-
if (m.post.match(/,(?!,).*\}/)) {
41609+
if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) {
41610+
rewrites++;
4156841611
str = m.pre + '{' + m.body + escClose + m.post;
4156941612
isTop = true;
4157041613
continue;
@@ -41584,7 +41627,7 @@ function expand_(str, max, maxLength, isTop) {
4158441627
let n = parseCommaParts(m.body);
4158541628
if (n.length === 1 && n[0] !== undefined) {
4158641629
// x{{a,b}}y ==> x{a}y x{b}y
41587-
n = expand_(n[0], max, maxLength, false).map(embrace);
41630+
n = expand_(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace);
4158841631
//XXX is this necessary? Can't seem to hit it in tests.
4158941632
/* c8 ignore start */
4159041633
if (n.length === 1) {
@@ -41610,12 +41653,13 @@ function expand_(str, max, maxLength, isTop) {
4161041653
values = [];
4161141654
let valuesLength = 0;
4161241655
outer: for (let j = 0; j < n.length; j++) {
41613-
const expanded = expand_(n[j], max, maxLength, false);
41656+
const expanded = expand_(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false);
4161441657
for (let k = 0; k < expanded.length; k++) {
4161541658
const v = expanded[k];
4161641659
if (dropsEmpties && !v)
4161741660
continue;
41618-
if (values.length >= max || valuesLength + v.length > maxLength) {
41661+
if (values.length >= max ||
41662+
valuesLength + v.length > maxLength) {
4161941663
break outer;
4162041664
}
4162141665
values.push(v);

0 commit comments

Comments
 (0)