CSRF bypass in builderio/qwik

Valid

Reported on

Apr 19th 2023


Description

URL parsing with Qwik uses the new URL(a, b) constructor. A little-known fact about this constructor is that if an attacker controls a they have complete control of the finally resolved URL.

For example:

const url = new URL(attacker_value, "http://localhost")

By entering //test.com, we can change the origin to resolve to http://test.com.

Qwik URL Resolution

The getUrl function is used in production and development node servers link.

export function getUrl(req: IncomingMessage) {
  const origin = ORIGIN ?? getOrigin(req);
  return new URL((req as any).originalUrl || req.url || '/', origin);
}

This follows the earlier vulnerable pattern, and the origin can be controlled.

Cloudflare, Vercel and other deployments which do not use this mechanism are not vulnerable.

Proof of Concept

Start any node Qwik Server.

For simplicity, I am using curl to simulate the request from the browser. In this case, the origin is "attacker.com". An actual attack would use the victim's web browser to send these requests and be unable to edit headers manually.

Observe curl -X POST http://localhost:5173/ -H "Origin: http://attacker.com" causes a CSRF error

Observe curl -X POST http://localhost:5173//attacker.com/ -H "Origin: http://attacker.com" does not cause a CSRF error!

The internal URL now points to http://attacker.com; Qwik thinks it's attacker.com!

Impact

Bypass of CSRF protections.

The result is the ability to modify user resources, provided they have an active session and are using SameSite: None for session cookies.

Occurrences

Bad new URL(a, b)

References

We are processing your report and will contact the builderio/qwik team within 24 hours. a month ago
builderio/qwik maintainer has acknowledged this report a month ago
Adam Bradley gave praise a month ago
The researcher's credibility has slightly increased as a result of the maintainer's thanks: +1
Adam Bradley
a month ago

Maintainer


Related: https://github.com/unjs/ufo/pull/126

Adam Bradley
a month ago

Maintainer


https://github.com/BuilderIO/qwik/pull/3862

Adam Bradley validated this vulnerability a month ago

https://github.com/BuilderIO/qwik/releases/tag/v0.104.0

OhB00 has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
Adam Bradley marked this as fixed in 0.104.0 with commit 09190b a month ago
Adam Bradley has been awarded the fix bounty
This vulnerability has been assigned a CVE
Adam Bradley published this vulnerability a month ago
http.ts#L23 has been validated
to join this conversation