June 25, 2026
Three Labs, Three Lessons: Wrapping Up Clickjacking on PortSwigger
A week ago, I finished the entire XSS Apprentice track on PortSwigger, nine labs of finding sinks and breaking out of contexts. Right after…

By Diya
2 min read
A week ago, I finished the entire XSS Apprentice track on PortSwigger, nine labs of finding sinks and breaking out of contexts. Right after that I moved into Clickjacking, a category that turned out to be a completely different kind of puzzle. No payloads, no sinks, no JavaScript injection. Just CSS, iframes, and figuring out how to make a real click land somewhere the victim never intended.
Three labs in, all solved, and each one taught me something different.
Lab 1: Basic clickjacking with CSRF token protection
This was the entry point into the whole category, and the first thing it taught me is that a CSRF token isn't the safety net I assumed it was. The lab's delete account button was protected by one, but clickjacking doesn't need to forge or steal anything, it just borrows the victim's own already authenticated click. Stack a transparent iframe of the real page under a decoy div, line it up with the button, and the token rides along for free since the victim's browser is the one submitting the form. Most of the actual work here was just getting the CSS positioning right, low opacity first to check alignment by hovering and watching for the pointer cursor, then dropping it to near-zero once everything lined up.
Lab 2: Clickjacking with form input data prefilled from a URL parameter
This one added a twist, the target form's email field could be prepopulated straight from a URL query parameter, so no script was needed inside the iframe at all, just a crafted link. The real lesson from this lab wasn't the prefilling though, it was something I didn't expect: the decoy div has no fixed width, so its clickable area is only as big as the text inside it. I tested alignment with placeholder text, switched it to the final "Click me" before delivering, and the lab kept failing for reasons that weren't obvious until I checked the access log and realized the click area had quietly shifted because the new text was a different width. Small detail, but it cost a fair bit of troubleshooting.
Lab 3: Clickjacking with a frame buster script
The last one introduced an actual defense, a frame buster script meant to detect framing and break out of it. Beating it didn't require outsmarting the script at all, just making sure it never got to run. Adding sandbox="allow-forms" to the iframe disables script execution by default while still letting the form submit normally, so the defense never even gets a chance to fire. This lab made the gap between client-side and server-side protections really obvious, anything depending on JavaScript running inside the page is, by definition, running on territory the attacker controls how to load.
Looking back
Coming from XSS, clickjacking forced a different mindset entirely. Instead of asking where input lands in the page, the question became where pixels land on the screen, and whether the defenses in place actually hold up once the victim's own click is the thing doing the work. The CSRF-token lab reframed what that protection is actually for. The prefilled-form lab was a reminder that even cosmetic details like decoy text length can break an otherwise correct exploit. And the frame buster lab made it clear that client-side defenses only work if the attacker lets them.
Three labs, three very different lessons, and a category that ended up being less about code and more about patience with pixels.