The vulnerability is a CSRF protection bypass in Qwik City, caused by inconsistent and flawed parsing of the Content-Type HTTP header. The core of the issue lies in the checkCSRF and isContentType functions within packages/qwik-city/src/middleware/request-handler/resolve-request-handlers.ts.
The checkCSRF function, which is intended to prevent cross-site request forgery attacks on form submissions, relied on the isContentType function to determine if a request had a content type typically used for forms (e.g., application/x-www-form-urlencoded, multipart/form-data, text/plain).
The original isContentType function was vulnerable in two ways:
- It performed a case-sensitive comparison of the content type.
- It only split the
Content-Type header value by a semicolon (;), ignoring commas (,).
This allowed an attacker to bypass the CSRF check by sending a request with a crafted Content-Type header, such as application/x-www-form-urlencoded, application/json or using different casing like Application/X-WWW-Form-Urlencoded. The isContentType function would fail to correctly identify it as a form submission, and consequently, checkCSRF would not perform the necessary origin check, allowing the malicious request to proceed.
Additionally, the parseRequest function in packages/qwik-city/src/middleware/request-handler/request-event.ts used a different logic to parse the Content-Type header, leading to the inconsistent interpretation mentioned in the advisory.
The patch addresses this vulnerability by:
- Introducing a new
getContentType function that normalizes the Content-Type header by converting it to lowercase and splitting by both comma and semicolon.
- Updating
isContentType to use this new robust function and perform a case-insensitive check.
- Modifying
checkCSRF to correctly identify simple requests that require CSRF protection.
- Updating
parseRequest to use getContentType for consistent header interpretation across the application.