Upgrade Dossier · express 4.17.1 → 5.1.0

Run 20260926-154709 Generated 2026-09-26T15:56:46Z
express 4.17.1 → 5.1.0
✅ Ready to merge
TEST SUITE STATUS TRANSITION
0 → 0
33 tests passing · 0 failing · 0 file groups reverted
2 CVEs closed MEDIUM severity ✓ Merge
Mergeable Pipeline Execution
Triage
Docs
Plan
Parallel Fix
Verify
Dossier
Human Gate
0
Call sites fixed
0
Files touched
0
Breaking changes
0 min
Total time
Test results
Before upgrade
✓ 0 passing ✗ Suite crashed (path-to-regexp error)
After upgrade
✓ 33 passing ✗ 0 failing
Vulnerabilities closed
ID Aliases Severity Summary Fixed in
GHSA-qw6h-vgh9-j6wx CVE-2024-43796 MEDIUM express vulnerable to XSS via response.redirect() 4.20.0 / 5.0.0
GHSA-rv95-896h-c2vc CVE-2024-29041 MEDIUM Express.js Open Redirect in malformed URLs 4.19.2 / 5.0.0-beta.3
Breaking changes handled (9)
bc-001 app.del() / router.del() removed routes/admin.js
Express 5 no longer supports router.del(). The shim router.del = router.delete was removed and the route was renamed to use router.delete() directly.
Fix applied
- router.del = router.delete;
- router.del('/users/:id', requireAdmin, function (req, res, next) {
+ router.delete('/users/:id', requireAdmin, function (req, res, next) {
bc-004 req.param(name) removed routes/admin.js · routes/tasks.js (8 sites)
req.param() has been removed. Each call was replaced with explicit access to req.params.<name> for route parameters.
Fix applied
- var id = parseInt(req.param('id'), 10);
+ var id = parseInt(req.params.id, 10);
bc-005 res.json(status, obj) signature removed app.js
res.json() no longer accepts a status code as the first argument. Use res.status(code).json(obj).
Fix applied
- res.json(status, { error: err.message || 'Internal Server Error' });
+ res.status(status).json({ error: err.message || 'Internal Server Error' });
bc-006 res.redirect('back') removed app.js
The magic string 'back' is no longer supported in res.redirect(). Use req.get('Referrer') || '/' instead.
Fix applied
- res.redirect('back');
+ res.redirect(req.get('Referrer') || '/');
bc-007 res.send(numericStatus) removed app.js · routes/tasks.js
res.send() with a lone numeric argument is no longer supported. Use res.sendStatus(code) instead.
Fix applied
- res.send(404);
+ res.sendStatus(404);
- res.send(201);
+ res.sendStatus(201);
- res.send(204);
+ res.sendStatus(204);
bc-009 Wildcard route paths must be named (/* → /*splat) app.js
Express 5 requires all wildcards to have a name. Bare /* routes now require a named wildcard like /*splat.
Fix applied
- app.get('/files/*', function (req, res) {
+ app.get('/files/*splat', function (req, res) {
- app.all('/api/*', function (req, res) {
+ app.all('/api/*splat', function (req, res) {
bc-010 req.params wildcard values are now arrays app.js
Wildcard params captured via /*name are now named and may return an array. req.params[0] is replaced with req.params.splat, joined with '/' if needed.
Fix applied
- var filePath = req.params[0];
+ var filePath = Array.isArray(req.params.splat) ? req.params.splat.join('/') : req.params.splat;
bc-011 req.query is now a read-only getter routes/tasks.js
req.query is no longer writable. Assignments to its properties are not allowed. Local variables are used instead.
Fix applied
- req.query.status = req.query.status.toLowerCase();
- req.query.priority = req.query.priority.toLowerCase();
+ var status = req.query.status ? req.query.status.toLowerCase() : undefined;
+ var priority = req.query.priority ? req.query.priority.toLowerCase() : undefined;
bc-013 Optional route parameter suffix ? removed (use braces) routes/admin.js · routes/tasks.js
Express 5 path-to-regexp no longer supports the :param? syntax for optional segments. Braces syntax {:param} / {/:param} is used instead.
Fix applied
- router.get('/:id/:field?', requireAuth, ...
+ router.get('/:id{/:field}', requireAuth, ...
- router.get('/logs/:level?', requireAdmin, ...
+ router.get('/logs{/:level}', requireAdmin, ...
Residual risk
No residual risk. All 9 breaking changes were handled and all 33 tests pass after the upgrade.
Reviewer checklist