security: upgrade express 4.22.2 + qs 6.15.2 resolution for dev-tool holdouts (Dependabot alert 1305) (#21434)

Closes the qs Dependabot alert —
[1305](https://github.com/twentyhq/twenty/security/dependabot/1305) — by
**upgrading express where possible** and using a **documented qs
resolution** only for the irreducible dev-only holdouts.

### What's vulnerable
`qs 6.14.x` (the `qs.stringify` DoS) is pulled by `express 4.22.1` /
`body-parser 1.x`. The fix is `qs 6.15.2`, and there's **no backport to
the 6.14 line**.

### Upgrade what we can (no resolution)
`express 4.22.2` / `body-parser 1.20.5` moved to the patched `qs
~6.15.1`. So this PR bumps the app + in-range tooling to **express
4.22.2**:
- twenty-server's stale direct pin `4.22.1 → 4.22.2` (its runtime HTTP
is already express 5.2.1 via `@nestjs/platform-express`; this just
patches the redundant direct dep — typecheck passes),
- nx / electron-forge / webpack-dev-server / companion follow via `yarn
up -R express body-parser`.

### Resolution only for the two holdouts
Two **dev-only** tools pin express *exactly* with no patched release on
a line we can use, so they still drag in `qs 6.14.2`:
- **verdaccio** `4.22.1` — express 5 only landed in the **v7 beta**
([verdaccio#5680](https://github.com/verdaccio/verdaccio/issues/5680),
[#2479](https://github.com/verdaccio/verdaccio/issues/2479)), **not**
backported to the 6.x line we use.
- **@mintlify/previewing** `4.22.0` — closed-source, latest still pins
4.22.0, no movement.

A `qs: 6.15.2` resolution covers those, documented with a top-level
`//resolutions` note and a removal trigger.

### Verification
- `yarn install --immutable` ✓; every `qs` resolves to `6.15.2`; express
app/tooling on `4.22.2` (only verdaccio/mintlify remain on old express,
neutralized by the resolution).
- `twenty-server` typecheck ✓ (90 files import express types;
4.22.1→4.22.2 is a patch).
- Non-exploitable in prod regardless (express/body-parser use
`qs.parse`, not the vulnerable `stringify`).
This commit is contained in:
Charles Bochet
2026-06-11 10:46:04 +02:00
committed by GitHub
parent 233a6f9fb1
commit 2da28cb03e
3 changed files with 45 additions and 81 deletions
+3 -1
View File
@@ -44,8 +44,10 @@
"pacote/tar": "npm:^7.5.16",
"@angular-devkit/core": "19.2.24",
"yeoman-environment": "6.0.1",
"@electron-forge/plugin-webpack/webpack-dev-server": "5.2.4"
"@electron-forge/plugin-webpack/webpack-dev-server": "5.2.4",
"qs": "6.15.2"
},
"//resolutions": "qs is pinned to 6.15.2 (CVE) for verdaccio + @mintlify/previewing, which pin old express 4.22.x; remove when they upgrade express",
"version": "0.2.1",
"nx": {},
"scripts": {
+1 -1
View File
@@ -97,7 +97,7 @@
"dompurify": "^3.4.0",
"dotenv": "16.4.5",
"email-reply-parser": "^2.3.5",
"express": "4.22.1",
"express": "4.22.2",
"express-session": "^1.18.2",
"file-type": "^21.3.2",
"fuse.js": "^7.1.0",
+41 -79
View File
@@ -28966,27 +28966,7 @@ __metadata:
languageName: node
linkType: hard
"body-parser@npm:~1.20.3":
version: 1.20.4
resolution: "body-parser@npm:1.20.4"
dependencies:
bytes: "npm:~3.1.2"
content-type: "npm:~1.0.5"
debug: "npm:2.6.9"
depd: "npm:2.0.0"
destroy: "npm:~1.2.0"
http-errors: "npm:~2.0.1"
iconv-lite: "npm:~0.4.24"
on-finished: "npm:~2.4.1"
qs: "npm:~6.14.0"
raw-body: "npm:~2.5.3"
type-is: "npm:~1.6.18"
unpipe: "npm:~1.0.0"
checksum: 10c0/569c1e896297d1fcd8f34026c8d0ab70b90d45343c15c5d8dff5de2bad08125fc1e2f8c2f3f4c1ac6c0caaad115218202594d37dcb8d89d9b5dcae1c2b736aa9
languageName: node
linkType: hard
"body-parser@npm:~1.20.5":
"body-parser@npm:~1.20.3, body-parser@npm:~1.20.5":
version: 1.20.5
resolution: "body-parser@npm:1.20.5"
dependencies:
@@ -34482,7 +34462,7 @@ __metadata:
languageName: node
linkType: hard
"express@npm:4.22.1, express@npm:^4.17.1, express@npm:^4.18.2, express@npm:^4.21.2":
"express@npm:4.22.1":
version: 4.22.1
resolution: "express@npm:4.22.1"
dependencies:
@@ -34521,43 +34501,7 @@ __metadata:
languageName: node
linkType: hard
"express@npm:5.2.1, express@npm:^5.1.0":
version: 5.2.1
resolution: "express@npm:5.2.1"
dependencies:
accepts: "npm:^2.0.0"
body-parser: "npm:^2.2.1"
content-disposition: "npm:^1.0.0"
content-type: "npm:^1.0.5"
cookie: "npm:^0.7.1"
cookie-signature: "npm:^1.2.1"
debug: "npm:^4.4.0"
depd: "npm:^2.0.0"
encodeurl: "npm:^2.0.0"
escape-html: "npm:^1.0.3"
etag: "npm:^1.8.1"
finalhandler: "npm:^2.1.0"
fresh: "npm:^2.0.0"
http-errors: "npm:^2.0.0"
merge-descriptors: "npm:^2.0.0"
mime-types: "npm:^3.0.0"
on-finished: "npm:^2.4.1"
once: "npm:^1.4.0"
parseurl: "npm:^1.3.3"
proxy-addr: "npm:^2.0.7"
qs: "npm:^6.14.0"
range-parser: "npm:^1.2.1"
router: "npm:^2.2.0"
send: "npm:^1.1.0"
serve-static: "npm:^2.2.0"
statuses: "npm:^2.0.1"
type-is: "npm:^2.0.1"
vary: "npm:^1.1.2"
checksum: 10c0/45e8c841ad188a41402ddcd1294901e861ee0819f632fb494f2ed344ef9c43315d294d443fb48d594e6586a3b779785120f43321417adaef8567316a55072949
languageName: node
linkType: hard
"express@npm:^4.22.1":
"express@npm:4.22.2, express@npm:^4.17.1, express@npm:^4.18.2, express@npm:^4.21.2, express@npm:^4.22.1":
version: 4.22.2
resolution: "express@npm:4.22.2"
dependencies:
@@ -34596,6 +34540,42 @@ __metadata:
languageName: node
linkType: hard
"express@npm:5.2.1, express@npm:^5.1.0":
version: 5.2.1
resolution: "express@npm:5.2.1"
dependencies:
accepts: "npm:^2.0.0"
body-parser: "npm:^2.2.1"
content-disposition: "npm:^1.0.0"
content-type: "npm:^1.0.5"
cookie: "npm:^0.7.1"
cookie-signature: "npm:^1.2.1"
debug: "npm:^4.4.0"
depd: "npm:^2.0.0"
encodeurl: "npm:^2.0.0"
escape-html: "npm:^1.0.3"
etag: "npm:^1.8.1"
finalhandler: "npm:^2.1.0"
fresh: "npm:^2.0.0"
http-errors: "npm:^2.0.0"
merge-descriptors: "npm:^2.0.0"
mime-types: "npm:^3.0.0"
on-finished: "npm:^2.4.1"
once: "npm:^1.4.0"
parseurl: "npm:^1.3.3"
proxy-addr: "npm:^2.0.7"
qs: "npm:^6.14.0"
range-parser: "npm:^1.2.1"
router: "npm:^2.2.0"
send: "npm:^1.1.0"
serve-static: "npm:^2.2.0"
statuses: "npm:^2.0.1"
type-is: "npm:^2.0.1"
vary: "npm:^1.1.2"
checksum: 10c0/45e8c841ad188a41402ddcd1294901e861ee0819f632fb494f2ed344ef9c43315d294d443fb48d594e6586a3b779785120f43321417adaef8567316a55072949
languageName: node
linkType: hard
"exsolve@npm:^1.0.7":
version: 1.0.8
resolution: "exsolve@npm:1.0.8"
@@ -48498,16 +48478,7 @@ __metadata:
languageName: node
linkType: hard
"qs@npm:^6.11.0, qs@npm:^6.11.1, qs@npm:^6.14.0, qs@npm:^6.14.1, qs@npm:^6.4.0, qs@npm:^6.7.0":
version: 6.15.0
resolution: "qs@npm:6.15.0"
dependencies:
side-channel: "npm:^1.1.0"
checksum: 10c0/ff341078a78a991d8a48b4524d52949211447b4b1ad907f489cac0770cbc346a28e47304455c0320e5fb000f8762d64b03331e3b71865f663bf351bcba8cdb4b
languageName: node
linkType: hard
"qs@npm:^6.15.2, qs@npm:~6.15.1":
"qs@npm:6.15.2":
version: 6.15.2
resolution: "qs@npm:6.15.2"
dependencies:
@@ -48516,15 +48487,6 @@ __metadata:
languageName: node
linkType: hard
"qs@npm:~6.14.0, qs@npm:~6.14.1":
version: 6.14.2
resolution: "qs@npm:6.14.2"
dependencies:
side-channel: "npm:^1.1.0"
checksum: 10c0/646110124476fc9acf3c80994c8c3a0600cbad06a4ede1c9e93341006e8426d64e85e048baf8f0c4995f0f1bf0f37d1f3acc5ec1455850b81978792969a60ef6
languageName: node
linkType: hard
"quansync@npm:^0.2.11":
version: 0.2.11
resolution: "quansync@npm:0.2.11"
@@ -55288,7 +55250,7 @@ __metadata:
dompurify: "npm:^3.4.0"
dotenv: "npm:16.4.5"
email-reply-parser: "npm:^2.3.5"
express: "npm:4.22.1"
express: "npm:4.22.2"
express-session: "npm:^1.18.2"
file-type: "npm:^21.3.2"
fuse.js: "npm:^7.1.0"