Bypassing SameSite Cookie Restrictions Using On-Site Gadgets – A Practical CSRF Bypass

6 views·5 min read·

SameSite=Strict Cookies are supposed to be a strong shield against CSRF (Cross-Site Request Forgery). When a cookie has this attribute, the browser refuses to send it on cross-site requests. In theory, this kills CSRF dead.

In practice, if the target site has a client-side redirect gadget that builds its redirect URL from user input, an attacker can turn a cross-site attack into what the browser sees as a same-site request, and the SameSite=Strict cookie gets sent anyway.

This post walks through exactly how that works, with a diagram to visualize it, and then a full step-by-step walkthrough of exploiting this on PortSwigger’s Web Security Academy lab.

How the Attack Works

Here’s the core idea in plain steps:

  1. Normal CSRF is blocked. If you host a malicious page on evil.com that makes a request to target.com, the browser marks that as a “cross-site” request. Since the cookie is SameSite=Strict, the browser won’t attach it.
  2. But some pages redirect using JavaScript. Some websites have a feature, like “you posted a comment, now we’ll send you back to the blog post“, that redirects the browser using client-side JavaScript (not a server-side Location header redirect). This script often reads a URL parameter (like postId) to decide where to send you next.
  3. The browser doesn’t know it’s a “redirect.” When JavaScript changes window.location, the browser doesn’t treat it as a continuation of the old request. It treats it as a fresh, brand-new request, initiated by the page itself, which is running on target.com. Since that new request originates from target.com going to target.com, it’s a same-site request. The SameSite=Strict cookie is included.
  4. The attacker abuses the parameter. If the JavaScript builds the redirect path unsafely from that URL parameter, an attacker can inject a path traversal sequence (like ../../my-account/change-email) into the parameter. The browser then “redirects”, really just makes a same-site request, to a completely different, attacker-chosen endpoint, cookies and all.
  5. Combine with a CSRF-able endpoint. If somewhere on the site there’s a sensitive action (like changing an email address) that accepts a GET request and has no CSRF token, the attacker now has everything needed: a way to force a same-site request, carrying valid session cookies, to that sensitive endpoint.

In short: the attacker never breaks SameSite. They trick the site into making the dangerous request “from itself.”

Step-by-Step: Exploiting the Lab

Now let’s actually do it. This walkthrough targets PortSwigger’s “Bypassing SameSite restrictions using on-site gadgets” lab.

Step 1: Study the Change Email Function

In Burp’s built-in browser, log in with your own lab account and try changing your email address normally.

Open Burp’s Proxy → HTTP history and find the POST /my-account/change-email request.

Notice there’s no CSRF token in this request, meaning it would be vulnerable to CSRF, if we could get the session cookie to travel cross-site.

Check the response to your POST /login request. You’ll see the session cookie is set with SameSite=Strict, which normally blocks that.

    Step 2: Find a Redirect Gadget

    Go to any blog post and leave a comment.

    You’ll land on /post/comment/confirmation?postId=x, and after a few seconds, get auto-redirected back to the blog post.

      In Burp’s history, notice this redirect is powered by a JavaScript file: /resources/js/commentConfirmationRedirect.js

      Open that script and check how it builds the redirect path, you’ll see it takes the postId parameter straight from the URL and uses it to construct the destination.

      Copy the confirmation URL from Burp, then manually visit it in your browser with a modified postId, like:

        /post/comment/confirmation?postId=foo

        You’ll briefly see the confirmation page, then get redirected to /post/foo – confirming your input controls the path.

        Now try a path traversal payload:

          /post/comment/confirmation?postId=1/../../my-account

          The browser normalizes this path and takes you to your account page. This proves you can force the browser to make a GET request to any endpoint on the site.

            Step 3: Confirm the Bypass Actually Sends Cookies

            On the exploit server, create a page with this script:

            <script>
                   document.location = "https://YOUR-LAB-ID.web-security-academy.net/post/comment/confirmation?postId=../my-account";
               </script>
              1. Store it, then view it yourself.
              2. You should land on your logged-in account page, proving the browser sent your session cookie even though the request technically started from the exploit server.

              Step 4: Build the Real Exploit

              1. Send POST /my-account/change-email to Burp Repeater.
              2. Right-click and choose Change request method, Burp converts it into a GET request.
              3. Send it and confirm the endpoint accepts email changes via GET too.
              4. Go back to your exploit server and update the script so the redirect target is the change-email endpoint instead:
                <script>
                     document.location = "https://YOUR-LAB-ID.web-security-academy.net/post/comment/confirmation?postId=1/../../my-account/change-email?email=pwned%40web-security-academy.net%26submit=1";
                 </script>
              

              Note two important details:

              • The submit parameter must be included, or the change won’t process.
              • The & between email and submit must be URL-encoded as %26, otherwise it breaks out of the postId parameter early.
              1. Test it on yourself first to confirm your email actually changes.
              2. Once confirmed, update the target email to something that isn’t yours.
              3. Deliver the exploit to the victim (click “Deliver exploit to victim” on the lab). After a short delay, the victim’s email gets changed, lab solved.

              If you enjoyed this walkthrough, then hit a like 🙂

              Leave a Reply

              Your email address will not be published. Required fields are marked *