The dev server now blocks unauthenticated /api/* access unless isSameOrigin(req) passes, but the current implementation is too weak:
function isSameOrigin(req) {
const origin = req.headers.origin || req.headers.referer || '';
return origin.includes(`localhost:${PORT}`) || origin.includes(`127.0.0.1:${PORT}`);
}
This trusts any Origin or Referer string that merely contains localhost:PORT or 127.0.0.1:PORT as a substring. It does not parse and compare the actual origin.
As a result, a foreign header such as:
Referer: https://evil.example/?next=http://127.0.0.1:8000/
is incorrectly accepted as same-origin.
Why this matters
This is not a strict same-origin check. It is a substring check on attacker-controlled header content.
That means /api/* endpoints are still reachable if the request carries a misleading Referer or Origin value containing the local dev URL somewhere inside the string.
Even if ordinary browser fetch() from unrelated sites may now be blocked in many cases, the server-side trust decision is still wrong and should be fixed. The current implementation is fragile and can be bypassed by forged headers or non-browser clients.
Confirmed reproduction
Server running at:
1. No headers: correctly blocked
curl -i "http://127.0.0.1:8000/api/check-url?url=https://example.com"
Response:
HTTP/1.1 403 Forbidden
...
Forbidden
2. Forged foreign Referer containing local URL substring: incorrectly allowed
curl -i "http://127.0.0.1:8000/api/check-url?url=https://example.com" \
-H "Referer: https://evil.example/?next=http://127.0.0.1:8000/"
Response:
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
...
{"status":0,"error":"unable to get local issuer certificate"}
The upstream TLS error is unrelated. The important part is that the request was accepted and forwarded instead of returning 403.
3. Same bypass works on /api/proxy
curl -i -X POST "http://127.0.0.1:8000/api/proxy" \
-H "Content-Type: application/json" \
-H "Referer: https://evil.example/?next=http://127.0.0.1:8000/" \
--data '{"url":"https://example.com","method":"GET","headers":{}}'
Response:
HTTP/1.1 502 Bad Gateway
Content-Type: application/json
Access-Control-Allow-Origin: *
...
{"error":"Upstream error: unable to get local issuer certificate"}
Again, the upstream certificate failure is not the issue. The issue is that the request bypassed the same-origin guard and reached the proxy logic.
Expected behavior
The server should only accept requests whose actual origin matches the local dev origin exactly.
Examples that should be accepted:
http://127.0.0.1:8000
http://localhost:8000
Examples that should be rejected:
https://evil.example/?next=http://127.0.0.1:8000/
https://127.0.0.1:8000.evil.example
- any unrelated origin containing the local URL as a substring
Suggested fix
Parse and compare exact origins instead of using substring matching.
For example:
function isSameOrigin(req) {
const allowed = new Set([
`http://127.0.0.1:${PORT}`,
`http://localhost:${PORT}`,
]);
if (req.headers.origin) {
return allowed.has(req.headers.origin);
}
if (req.headers.referer) {
try {
return allowed.has(new URL(req.headers.referer).origin);
} catch {
return false;
}
}
return false;
}
It would also be reasonable to rely only on Origin for API endpoints and avoid Referer fallback entirely unless there is a strong compatibility reason.
The dev server now blocks unauthenticated
/api/*access unlessisSameOrigin(req)passes, but the current implementation is too weak:This trusts any
OriginorRefererstring that merely containslocalhost:PORTor127.0.0.1:PORTas a substring. It does not parse and compare the actual origin.As a result, a foreign header such as:
is incorrectly accepted as same-origin.
Why this matters
This is not a strict same-origin check. It is a substring check on attacker-controlled header content.
That means
/api/*endpoints are still reachable if the request carries a misleadingRefererorOriginvalue containing the local dev URL somewhere inside the string.Even if ordinary browser
fetch()from unrelated sites may now be blocked in many cases, the server-side trust decision is still wrong and should be fixed. The current implementation is fragile and can be bypassed by forged headers or non-browser clients.Confirmed reproduction
Server running at:
1. No headers: correctly blocked
curl -i "http://127.0.0.1:8000/api/check-url?url=https://example.com"Response:
2. Forged foreign Referer containing local URL substring: incorrectly allowed
Response:
The upstream TLS error is unrelated. The important part is that the request was accepted and forwarded instead of returning
403.3. Same bypass works on
/api/proxyResponse:
Again, the upstream certificate failure is not the issue. The issue is that the request bypassed the same-origin guard and reached the proxy logic.
Expected behavior
The server should only accept requests whose actual origin matches the local dev origin exactly.
Examples that should be accepted:
http://127.0.0.1:8000http://localhost:8000Examples that should be rejected:
https://evil.example/?next=http://127.0.0.1:8000/https://127.0.0.1:8000.evil.exampleSuggested fix
Parse and compare exact origins instead of using substring matching.
For example:
It would also be reasonable to rely only on
Originfor API endpoints and avoidRefererfallback entirely unless there is a strong compatibility reason.