Bug Description
The custom CSRF protection function validateCsrf in src/lib/csrf.ts attempts to validate the HTTP Referer header against a list of allowed origins. However, it uses a naive string matching implementation: referer.startsWith(a).
If an allowed origin a is https://devtrack.com, the check does not verify a domain boundary (like a trailing slash). An attacker can register a domain like https://devtrack.com.attacker.com and host a malicious CSRF payload targeting state-changing API routes. The victim's browser will send Referer: https://devtrack.com.attacker.com/exploit, which incorrectly evaluates to true under .startsWith(). The CSRF protection is silently bypassed.
Steps to Reproduce
- Serve a local instance or use the production API.
- Send a
POST request to a state-changing API route protected by validateCsrf.
- Set the
Referer header to https://devtrack.com.attacker.com.
- Observe that the CSRF validation successfully passes.
Affected Area
API Routes
Screenshots
No response
Browser & OS
No response
Environment
Both
Additional Context
Suggested Fix:
- Use the native
URL constructor to parse the referer header: const refUrl = new URL(referer);.
- Validate exactly against the origin:
if (allowed.includes(refUrl.origin)) return { valid: true };.
- Ensure trailing slashes are consistently handled before comparison.
Bug Description
The custom CSRF protection function
validateCsrfinsrc/lib/csrf.tsattempts to validate the HTTPRefererheader against a list of allowed origins. However, it uses a naive string matching implementation:referer.startsWith(a).If an allowed origin
aishttps://devtrack.com, the check does not verify a domain boundary (like a trailing slash). An attacker can register a domain likehttps://devtrack.com.attacker.comand host a malicious CSRF payload targeting state-changing API routes. The victim's browser will sendReferer: https://devtrack.com.attacker.com/exploit, which incorrectly evaluates totrueunder.startsWith(). The CSRF protection is silently bypassed.Steps to Reproduce
POSTrequest to a state-changing API route protected byvalidateCsrf.Refererheader tohttps://devtrack.com.attacker.com.Affected Area
API Routes
Screenshots
No response
Browser & OS
No response
Environment
Both
Additional Context
Suggested Fix:
URLconstructor to parse therefererheader:const refUrl = new URL(referer);.if (allowed.includes(refUrl.origin)) return { valid: true };.