[security] deps: vulnerability in brace-expansion (high) #103
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/simpl-liste#103
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Détection
Détecté par le Défenseur defenseur-simpl-liste le 2026-07-27T05:15:10.727Z. Confirmé par
npm auditlive surmaster.Findings
defenseur-simpl-liste-deps-npm-audit-simpl-liste-brace-expansion>=2.0.0 <2.1.2)<=5.0.7)Trois majeurs cohabitent dans l'arbre, tirés par des
minimatchdifférents :1.1.13glob@7 > minimatch@3 > brace-expansion(react-native codegen, @expo/cli dev-middleware, babel-jest)2.1.0@expo/cli > minimatch@9 > brace-expansion5.0.6@expo/fingerprint > minimatch@10 > brace-expansionRésolution suggérée
Non trivial — la CVE OOM (
<=5.0.7) n'a de fix qu'en 5.0.8 ; il n'y a pas de patch backporté en 1.x ni 2.x. Deux options :"brace-expansion": "^5.0.8"— à valider pour régression : il écraserait les instances 1.x/2.x, or minimatch 3.x attendbrace-expansion@^1.x. Tester le dev server + build EAS avant de merger.minimatch/globbumper leur borne, puis re-résoudre. Vu la surface build-time nulle, l'attente est acceptable.npm auditrapportefixAvailable: true(non-major), mais tracer l'arbre (npm ls brace-expansion) avant tout override blanket — cf. gotcha « override scope vs blanket ».Issue créée par
/analyse-vulnerabilitedepuis le rapport du Défenseur defenseur-simpl-liste (2026-07-27T05:15:10.727Z), réconcilié avecnpm auditlive surmaster. Le Défenseur ne porte pas encore l'étataccepted(le rapport est régénéré à chaque scan, éditer le JSON est un no-op). Pour un faux positif : fermer l'issue avec un commentaire d'analyse. Pour une vraie cause racine côté scanner : ouvrir une issue dansagent-defenseurs.Analyse (/analyze) — accepté comme non corrigeable in-place
Exploration des sites d'appel réels : l'override blanket
brace-expansion: ^5.0.8est cassant, et aucun fix ne metnpm audità 0 sans risque.Preuve — rupture de contrat CJS entre majeurs
1.1.13×4glob@7,@react-native/codegen,rimraf@3,test-exclude)module.exports = expandTop— export défaut2.1.0@expo/cli)module.exports = expandTop— export défaut5.0.6@expo/fingerprint)exports.expand,__esModule:true— export nommévar expand = require('brace-expansion'); expand(pattern)→ avec 5.x,require()renvoie{expand, __esModule}→TypeError: expand is not a function.__importDefault(require("brace-expansion")).default(pattern)→ 5.x a__esModule:true→.defaultestundefined→TypeError.^5.0.8casserait donc le bundling (expo start) : cheminreact-native+@react-native/codegen(Metro/codegen),glob/rimraf,@expo/cli.Pourquoi aucun fix propre
<=5.0.7) corrigée seulement en 5.0.8, aucun backport 1.x/2.x.1.1.13/2.1.0sont déjà les têtes de leur majeur (patchées pour la ReDoS antérieure) → non remontables in-place sans saut de majeur cassant.@expo/fingerprint > brace-expansion ^5.0.8(minimatch@10, export nommé → compatible) corrige la seule instance 5.x mais laisse1.1.13/2.1.0→npm auditreste rouge. Valeur limitée.glob@7/rimraf@3, blast radius élevé.Surface réelle
Les 3 instances sont dev/build-time (
glob/rimraf/test-exclude/@expo/cli fingerprint), opérant sur des chemins de fichiers locaux de confiance. L'OOM n'est pas déclenchable par un tiers externe → surface réelle nulle dans le modèle de menace de l'app livrée (cohérent avec le raisonnement « dev-tooling-only » de #100).Décision
Accepté comme hardening différé — fermé. À ré-évaluer quand
glob/rimraf/minimatchbumperontbrace-expansionen amont. Le Défenseur re-remontera ce finding à chaque scan (l'étatacceptedn'existe pas encore côté scanner) — c'est attendu, pas une régression.Précédent : #100 a splitté
js-yamlen 2 scopes (^4/^3) plutôt qu'un blanket pour ce même cas « deux majeurs incompatibles ».Rouverte -- debloquee par la technique version-scoped
Le verdict initial (non fixable in-place) tenait pour un override blanket
brace-expansion: ^5.0.8(qui force 5.x sur minimatch@3/@9 attendant l'export par defaut ->TypeErrorau bundling) et pour l'override scope partiel@expo/fingerprint(incomplet).La solution manquee : des overrides version-scoped par majeur, qui bumpent chaque majeur DANS son majeur, preservant le contrat d'API :
Les tetes patchees existent desormais dans chaque majeur (1.1.18, 2.1.4, 5.0.9). Resultat :
1.1.13->1.1.18(x4, export defaut preserve),2.1.0->2.1.4(export defaut),5.0.6->5.0.9(export nomme). Aucuninvalid.Verifie :
minimatch@3(celui qui levait TypeError sous blanket) resout correctement --mm("src/foo.js","src/*.js") == true. Smoke test 11/11. Fix dans la PR a venir.