h3 icon indicating copy to clipboard operation
h3 copied to clipboard

Common pattern with `readBody` may lead to CSRF

Open OhB00 opened this issue 1 year ago • 0 comments

Environment

N/A

Reproduction

The following pattern for creating endpoints is common, and may lead to a CSRF attack, provided it is a GET/POST handler, and only requires strings, or arrays of strings in the body.

The following is an example of what a vulnerable handler might look like:

export default defineEventHandler(async e => {
  // Authenticated endpoint
  await VerifyAuthenticationHere(e)

  // Assumption here that content-type is validated.
  const body = await readBody(e)

  // Optional validation here ...

  // Some sensitive action that relies upon body
  if (body.action === "update") {
    await UpdateUser(body.new_username)
  }
})

Describe the bug

The readBody utility will accept multiple different content type's, including application/json application/x-www-form-urlencoded and text/plain.

There is an assumption that the readBody handler will only emit an object for the application/json content type, however, this also occurs for application/x-www-form-urlencoded.

This has implications for security as cross-site requests can be sent when using the application/x-www-form-urlencoded, but they cannot be sent when using application/json.

If readBody is called without appropriate CSRF protections, or without verifying the content-type header, the application may be at risk of a CSRF attack.

Additional context

The following handler is an example of how an attacker could exploit one of these issues:

await fetch('https://whatever.io/api/edit', {
    method: 'POST',
    headers:{
      'Content-Type': 'application/x-www-form-urlencoded'
    },    
    body: new URLSearchParams({
        'username': 'hacked!',
    }),
    mode: 'no-cors'
}

Logs

No response

OhB00 avatar Sep 02 '24 17:09 OhB00