← back to Rentv
rentv: terminal URIError handler → 400 for malformed-% URLs (TK-10685 hardening)
a61267f0184e42e6c9cd9429b29ff7e350c22488 · 2026-08-24 10:35:31 -0700 · Steve Abrams
The two hand-guarded decodeURIComponent(req.path) sites (014a1608) fix the
static/inject paths, but a malformed %-escape can still throw a URIError from
Express's router when decoding a route param — downstream of those guards, so it
would surface as a 500. Add a terminal error-handling middleware that returns a
clean 400 for any URIError. Belt-and-suspenders over the path guards.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit a61267f0184e42e6c9cd9429b29ff7e350c22488
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 24 10:35:31 2026 -0700
rentv: terminal URIError handler → 400 for malformed-% URLs (TK-10685 hardening)
The two hand-guarded decodeURIComponent(req.path) sites (014a1608) fix the
static/inject paths, but a malformed %-escape can still throw a URIError from
Express's router when decoding a route param — downstream of those guards, so it
would surface as a 500. Add a terminal error-handling middleware that returns a
clean 400 for any URIError. Belt-and-suspenders over the path guards.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
server.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/server.js b/server.js
index 1b7f010f..46d868c2 100644
--- a/server.js
+++ b/server.js
@@ -2894,4 +2894,16 @@ app.use((req, res, next) => {
// LABJ directory headshots (INTERNAL admin-only; scanned Book-of-Lists portraits, not for public surfaces)
app.use('/labj-photos', adminOnly, express.static(path.join(DATA, 'labj2026-photos')));
app.use(express.static(PUB, { extensions: ['html'] }));
+// TK-10685: a malformed %-escape in the URL (e.g. /admin%, /foo%) makes Express's
+// router / express.static throw a URIError while decoding the path — downstream of
+// the two hand-guarded decodeURIComponent(req.path) sites above, so those guards
+// can't catch it and it surfaced as a 500. Terminal error handler returns a clean
+// 400 instead. Not a crash and not a security bypass; low-severity hygiene.
+app.use((err, req, res, next) => {
+ if (err instanceof URIError) {
+ if (res.headersSent) return next(err);
+ return res.status(400).type('text/plain').send('Bad Request: malformed URL');
+ }
+ return next(err);
+});
app.listen(PORT, () => console.log('rentv (unified site — user/admin tiers, live data) on ' + PORT));
← 675f26bb auto-data-snapshot: 2026-08-24T10:08:33 (7 data files) — dat
·
back to Rentv
·
auto-data-snapshot: 2026-08-24T10:40:26 (7 data files) — dat af2b3ce6 →