fix(standalone): harden input validation on siteKey, siteverify body,…#258
fix(standalone): harden input validation on siteKey, siteverify body,…#258dvynshuu wants to merge 5 commits into
Conversation
… and unblock-ip
- Add regex guard (^[a-f0-9]{10}$) on siteKey path params in cap routes to prevent malformed keys from reaching Redis
- Add Elysia t.Object body schema to siteverify endpoint (was the only endpoint missing type validation, could crash on non-string input)
- Fix unblock-ip handler to return 400 for invalid block types instead of silently falling through (matching block-ip behavior)
- The test 'returns 404 for unknown site key' was failing in CI because it used the string 'nonexistent_key', which failed the new regex validation and returned 400 instead of 404. Changed to use a compliant 10-hex-char string (0000000000) so it bypasses the regex check and successfully hits the Redis query to test the 404 code path.
|
do you have benchmark results for that regex? is it vulnerable to redos? |
|
Good morning to you live in airport
…On Sat, 16 May 2026, 7:19 pm tiago, ***@***.***> wrote:
*tiagozip* left a comment (tiagozip/cap#258)
<#258 (comment)>
do you have benchmark results for that regex? is it vulnerable to redos?
—
Reply to this email directly, view it on GitHub
<#258 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/B5KYPUNTWTI26QQJXO7CED343CWLFAVCNFSM6AAAAACZATLNJCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DINRXG4ZDMNJVG4>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
|
No benchmark results were included in the PR initially, but I wrote a quick test to measure it against Bun's engine. To answer your second question first: No, it is mathematically impossible for this regex to be vulnerable to ReDoS. ReDoS vulnerabilities require a regex engine to perform exponential backtracking. Backtracking only happens when a regex has overlapping alternations (e.g., (a|a)+) or overlapping unbounded quantifiers (e.g., (a+)+). The regex /^[a-f0-9]{10}$/ contains: ^ and $ (strict bounds) Here are the benchmark results running 10,000,000 iterations for each case on Bun v1.1.20+ (which uses WebKit's incredibly fast RegExp engine under the hood). Even checking against a malicious string of 100,000 characters is virtually instantaneous because it fails instantly at the 11th character or end-of-string bound. const SITE_KEY_RE = /^[a-f0-9]{10}$/; Results (10 million iterations each): [339.88ms] Valid 10-char hex string |
|
on 1, did you add an optional catch for the old schema? |
…ve old error format
|
Yes, good catch! I just pushed a follow-up commit to fix that. |
|
uh no, that's not what i meant. on previous cap standalone versions, a key id parameter was also required. this would block everyone still sending a key id. |
|
Ah, I see exactly what you mean! Because Elysia strictly validates objects and strips/rejects unknown properties by default, the new schema would have thrown a 400 Validation Error if anyone passed legacy fields like keyId in the JSON body. |
Description
This PR introduces three focused input validation and defense-in-depth improvements to the standalone server to harden its security posture.
1. Added schema validation to
/siteverifyThe
siteverify.jsendpoint was the only route missing Elysia'st.Objectbody schema validation. Because it relied on raw destructuring (const { secret, response } = body;), passing non-string payloads (e.g., arrays or objects) would cause unhandledTypeErrorexceptions (e.g.,response.split is not a function), potentially leading to unexpected crashes.t.Objectbody and params validation to guarantee correct types before the handler executes.2. Guarded
siteKeypath params against format manipulationThe
siteKeypath parameter is used extensively in direct Redis key construction (e.g.,key:${siteKey}). Previously, any arbitrary string was accepted as asiteKeyparameter./^[a-f0-9]{10}$/) viaonBeforeHandleto ensure that only properly formatted 10-character hex keys (matching therandomBytes(5)generation logic) can hit the database. This eliminates any risk of key namespace pollution or Redis protocol injection.3. Fixed fallthrough bug in
unblock-ipIn
server.js, theblock-iphandler correctly returns a400error if an unknowntypeis passed. However, theunblock-iphandler silently fell through and treated unknown types as anip(key = body.ip;).unblock-ipwithblock-ipto return a400 Bad Requestfor invalid block types, preventing accidental unblocking of the wrong entries.Type of Change
Checklist
biome checkand fixed all warnings/errors