Repository navigation
chore(Yarn): bump vulns for brace-expansion, fast-uri - BED-9133 - #3093
Conversation
📝 WalkthroughWalkthroughThe dependency resolutions update ChangesDependency remediation
Estimated code review effort: 1 (Trivial) | ~5 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.yarnrc.yml:
- Around line 29-31: Update the npmPreapprovedPackages entries for
brace-expansion and fast-uri to exact package-version descriptors, without the
npm: protocol, so preapproval applies only to the patched versions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: 12a0d54a-3a23-4c7d-8f2b-2a6d0962cfba
⛔ Files ignored due to path filters (4)
.yarn/cache/brace-expansion-npm-5.0.8-08bf144160-75d2d2ebc8.zipis excluded by!**/.yarn/**,!**/*.zip.yarn/cache/brace-expansion-npm-5.0.9-2717df6b49-d8683d6129.zipis excluded by!**/.yarn/**,!**/*.zip.yarn/cache/fast-uri-npm-3.1.5-39a8d368d6-784bef687c.zipis excluded by!**/.yarn/**,!**/*.zipyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (2)
.yarnrc.ymlpackage.json
| npmPreapprovedPackages: | ||
| - brace-expansion | ||
| - fast-uri |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- .yarnrc.yml ---'
cat -n .yarnrc.yml
printf '%s\n' '--- package manifests containing target packages ---'
rg -n -C 3 '"(brace-expansion|fast-uri)"|brace-expansion|fast-uri' --glob 'package.json' --glob 'yarn.lock' --glob '*.yml' --glob '*.yaml' .
printf '%s\n' '--- Yarn metadata and version references ---'
rg -n -i -C 2 'npmPreapprovedPackages|package gate|preapproved' . --glob '!node_modules' --glob '!build' --glob '!dist'Repository: SpecterOps/BloodHound
Length of output: 5200
🌐 Web query:
Yarn 4 npmPreapprovedPackages exact package descriptor package-name pattern semantics npmMinimalAgeGate
💡 Result:
In Yarn 4, npmMinimalAgeGate and npmPreapprovedPackages are security features designed to prevent the installation of recently published packages, which may be malicious [1][2][3]. npmMinimalAgeGate This setting restricts the installation of packages to those published at least N days (or specified duration) prior to the current time [1]. It defaults to 1d [1]. It can be bypassed for a single command using the --no-time-gate flag [1]. npmPreapprovedPackages This setting defines an array of packages or patterns that are excluded from the npmMinimalAgeGate check [4][5]. It supports several types of identifiers, utilizing micromatch for glob pattern matching [2][3]: 1. Package Descriptors: You can specify package descriptors (e.g., typescript@^5.0.0) [2][6][3]. 2. Glob Patterns: You can use micromatch glob patterns to match package names or descriptors (e.g., @my-scope/@ or @aws-sdk/) [2][6][3]. 3. Exact Locators: The implementation also supports exact match on package locators, which identify specific versions (e.g., @aws-sdk/types@3.877.0 or @aws-sdk/types@npm:3.877.0) [2][3]. Configuration is performed in the.yarnrc.yml file [4][6]. For example: npmPreapprovedPackages: - "typescript@^5.0.0" - "@my-scope/@*" When evaluating candidates during resolution, the npm semver resolver checks these settings to determine if a package is permitted for installation [2][3].
Citations:
- 1: https://yarnpkg.com/features/security
- 2: feat: implement
npmMinimalAgeGateandnpmPreapprovedPackagesconfig options yarnpkg/berry#6901 - 3: yarnpkg/berry@8e84598
- 4: https://yarnpkg.com/configuration/yarnrc
- 5: https://github.com/yarnpkg/berry/blob/b223e69f6b5eb899c2e1a140f883a9f15252df2f/packages/plugin-npm/sources/index.ts
- 6: https://v6.yarnpkg.com/configuration/yarnrc.html
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- Yarn configuration references ---'
rg -n -C 5 'npmPreapprovedPackages|npmMinimalAgeGate' .yarn . --glob '*.cjs' --glob '*.js' --glob '*.json' --glob '*.md' --glob '*.yml' --glob '*.yaml' 2>/dev/null || true
printf '%s\n' '--- Relevant lockfile selectors and resolutions ---'
sed -n '7168,7185p' yarn.lock
sed -n '9418,9434p' yarn.lockRepository: SpecterOps/BloodHound
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
p = Path(".yarn/releases/yarn-4.13.0.cjs")
text = p.read_text()
needles = [
"npmPreapprovedPackages",
'function h0t',
'function g0t',
]
for needle in needles:
print(f"--- {needle} ---")
start = text.find(needle)
if start < 0:
print("not found")
continue
lo = max(0, start - 1200)
hi = min(len(text), start + 1800)
print(text[lo:hi])
PY
printf '%s\n' '--- concise matching implementation references ---'
rg -o -n '.{0,180}npmPreapprovedPackages.{0,260}|.{0,180}function h0t.{0,700}|.{0,180}function g0t.{0,300}' .yarn/releases/yarn-4.13.0.cjsRepository: SpecterOps/BloodHound
Length of output: 10650
🌐 Web query:
site:yarnpkg.com/configuration/yarnrc npmPreapprovedPackages "npm:"
💡 Result:
The npmPreapprovedPackages setting is a configuration option specifically for Yarn, not for the npm CLI [1]. It is defined in the.yarnrc.yml configuration file [1]. This setting allows you to specify an array of package descriptors or glob patterns for package names that should be excluded from all package gates [1]. When a package matches one of these patterns, it is exempted from evaluation by any active package gates, meaning it will not be restricted or checked by them [1].
Citations:
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
text = Path(".yarn/releases/yarn-4.13.0.cjs").read_text()
needles = ["tryParseDescriptor", "parseDescriptor", "validRange"]
for needle in needles:
positions = []
start = 0
while True:
pos = text.find(needle, start)
if pos < 0:
break
positions.append(pos)
start = pos + 1
print(f"{needle}: {len(positions)} occurrences")
for pos in positions[:8]:
print(text[max(0, pos-180):pos+420])
print("---")
PYRepository: SpecterOps/BloodHound
Length of output: 13562
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
text = Path(".yarn/releases/yarn-4.13.0.cjs").read_text()
for pattern in [r'function T2\([^)]*\)\{', r'function E0\([^)]*\)\{', r'function Mn\([^)]*\)\{']:
m = re.search(pattern, text)
print(f"--- {pattern} ---")
if not m:
print("not found")
continue
print(text[m.start():m.start()+1800])
PYRepository: SpecterOps/BloodHound
Length of output: 5655
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
text = Path(".yarn/releases/yarn-4.13.0.cjs").read_text()
for pattern in [
r'var NZe=',
r'var FZe=',
r'function dl\([^)]*\)\{',
]:
print(f"--- {pattern} ---")
m = re.search(pattern, text)
if not m:
print("not found")
continue
print(text[m.start():m.start()+1400])
PYRepository: SpecterOps/BloodHound
Length of output: 1645
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
yarn = Path(".yarn/releases/yarn-4.13.0.cjs").read_text()
config = Path(".yarnrc.yml").read_text()
package = Path("package.json").read_text()
# These checks model the relevant bundled Yarn 4.13.0 logic:
# - bare descriptors have range "unknown" and match every version
# - validRange rejects ranges containing ":"
# - exact semver ranges match only the same version
def descriptor(entry):
if "@" not in entry or entry.startswith("@") and entry.count("@") == 1:
return entry, "unknown"
name, version = entry.rsplit("@", 1)
return name, version
def matches(entry, name, version):
ident, range_ = descriptor(entry)
if ident != name:
return False
if range_ == "unknown":
return True
if ":" in range_:
return False
return range_ == version
entries = re.findall(r"^\s*-\s+(.+?)\s*$", config, re.M)
entries = [e.strip('"\'') for e in entries if e in ("brace-expansion", "fast-uri") or "brace-expansion@" in e or "fast-uri@" in e]
versions = {
"brace-expansion": re.search(r'"brace-expansion":\s*"([^"]+)"', package).group(1),
"fast-uri": re.search(r'"fast-uri":\s*"([^"]+)"', package).group(1),
}
candidates = [
"brace-expansion",
"fast-uri",
"brace-expansion@npm:5.0.9",
"fast-uri@npm:3.1.5",
"brace-expansion@5.0.9",
"fast-uri@3.1.5",
]
for entry in candidates:
name = entry.split("@", 1)[0]
if name.startswith(""):
target = versions.get(name)
else:
target = None
print(f"{entry!r}: current-version-match={matches(entry, name, target) if target else False}")
assert matches("brace-expansion", "brace-expansion", "5.0.9")
assert matches("brace-expansion", "brace-expansion", "99.0.0")
assert matches("fast-uri", "fast-uri", "3.1.5")
assert matches("fast-uri", "fast-uri", "99.0.0")
assert not matches("brace-expansion@npm:5.0.9", "brace-expansion", "5.0.9")
assert not matches("fast-uri@npm:3.1.5", "fast-uri", "3.1.5")
assert matches("brace-expansion@5.0.9", "brace-expansion", "5.0.9")
assert matches("fast-uri@3.1.5", "fast-uri", "3.1.5")
assert not matches("brace-expansion@5.0.9", "brace-expansion", "5.0.10")
assert not matches("fast-uri@3.1.5", "fast-uri", "3.1.6")
print("all assertions passed")
PYRepository: SpecterOps/BloodHound
Length of output: 470
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
yarn = Path(".yarn/releases/yarn-4.13.0.cjs").read_text()
config = Path(".yarnrc.yml").read_text()
package = Path("package.json").read_text()
def descriptor(entry):
if "@" not in entry:
return entry, "unknown"
return entry.rsplit("@", 1)
def matches(entry, name, version):
ident, range_ = descriptor(entry)
if ident != name:
return False
if range_ == "unknown":
return True
if ":" in range_:
return False
return range_ == version
versions = {
"brace-expansion": re.search(r'"brace-expansion":\s*"([^"]+)"', package).group(1),
"fast-uri": re.search(r'"fast-uri":\s*"([^"]+)"', package).group(1),
}
for entry in [
"brace-expansion",
"fast-uri",
"brace-expansion@npm:5.0.9",
"fast-uri@npm:3.1.5",
"brace-expansion@5.0.9",
"fast-uri@3.1.5",
]:
name = entry.split("@", 1)[0]
print(f"{entry!r}: {matches(entry, name, versions[name])}")
assert matches("brace-expansion", "brace-expansion", "99.0.0")
assert matches("fast-uri", "fast-uri", "99.0.0")
assert not matches("brace-expansion@npm:5.0.9", "brace-expansion", "5.0.9")
assert not matches("fast-uri@npm:3.1.5", "fast-uri", "3.1.5")
assert matches("brace-expansion@5.0.9", "brace-expansion", "5.0.9")
assert matches("fast-uri@3.1.5", "fast-uri", "3.1.5")
print("all assertions passed")
PYRepository: SpecterOps/BloodHound
Length of output: 338
Limit preapproval to the patched versions.
Bare package names match every version. Use exact descriptors without the npm: protocol:
npmPreapprovedPackages:
- - brace-expansion
- - fast-uri
+ - "brace-expansion@5.0.9"
+ - "fast-uri@3.1.5"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| npmPreapprovedPackages: | |
| - brace-expansion | |
| - fast-uri | |
| npmPreapprovedPackages: | |
| - "brace-expansion@5.0.9" | |
| - "fast-uri@3.1.5" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.yarnrc.yml around lines 29 - 31, Update the npmPreapprovedPackages entries
for brace-expansion and fast-uri to exact package-version descriptors, without
the npm: protocol, so preapproval applies only to the patched versions.
Description
Bump brace-expansions and fast-uri up from vulnerable versions
Motivation and Context
Resolves BED-9133
How Has This Been Tested?
Manually
Types of changes
Checklist:
Summary by CodeRabbit