Description
Why search for the flag when I can make a bookmarklet to print it for me?
Setup
Browse to the challenge page and find the flag!
Copy the bookmarklet code displayed on the page to inspect it.
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
"picoctf") character-by-character (mod 256) to recover the flag, then pops the result via alert().Step 1Create a bookmarklet manually
ObservationThe page hands you a snippet beginning with javascript: and calls it a bookmarklet. The intended path is saving it as a browser bookmark and clicking it while on the challenge page.Bookmark any page, edit that bookmark, and replace its URL with the JavaScript snippet you copied. When you click the bookmark, the code decrypts the encrypted flag string embedded on the page (using the key "picoctf" with a repeating subtraction mod 256) and shows the result in an alert.bashjavascript:(function(){ /* bookmarklet code from challenge page */ })();What didn't work first
Tried: Type the bookmarklet URL directly into the browser address bar and press Enter
Browsers strip the javascript: scheme out of the address bar as an anti-phishing measure, so you get a blank page or nothing at all. It runs only from a saved bookmark. Chrome, Firefox, and Safari all block the pasted form by default.
Tried: Open the bookmarklet snippet in a new tab by right-clicking and choosing 'Open in new tab'
The code references an encrypted flag variable that belongs to the challenge page. In a blank tab that variable does not exist and you get a reference error. It has to run in the page's own context, where the encrypted bytes are already loaded.
Learn more
A bookmarklet is a browser bookmark whose URL begins with
javascript:instead ofhttps://. When you click it, the browser executes the JavaScript in the context of the currently open page, giving the code access to the page's DOM, cookies, and variables.The IIFE (Immediately Invoked Function Expression) wrapping (the
(function(){})()pattern) is convention rather than strict requirement. For a one-linealert()it changes nothing, but it's a good habit because it isolates any helper variables from the page's globals.In security contexts, bookmarklets demonstrate how powerful in-page JavaScript can be: the same mechanism can read cookies, modify the DOM, or exfiltrate data. This is why Content Security Policy (CSP) headers exist to restrict inline script execution, and why browser extensions go through permission review.
Step 2Run it in a JS console instead
ObservationThe bookmarklet is plain JavaScript wrapped in an IIFE that ends with alert(). Paste it into the DevTools console on the challenge page and the decryption loop runs without creating a bookmark at all.Open DevTools (F12) or an online JavaScript runner, paste the snippet, and run it. The script simply calls alert() with the flag, so nothing else is required.js// Paste the full bookmarklet code from the challenge page into the console and press Enter. The decryption loop will run and call alert() with the recovered flag.What didn't work first
Tried: Paste only the inner function body without the IIFE wrapper into the console
Drop the outer function wrapper and the declarations inside leak into the page's global scope, where they can shadow existing variables and derail the loop. Worse, a top-level return throws a syntax error in the console. Keep the IIFE, or use the snippet exactly as given.
Tried: Run the snippet in an isolated online JavaScript sandbox like JSFiddle or CodePen instead of the browser console on the challenge page
The loop reads an encrypted array that the challenge page embedded as a global. An external sandbox starts with a clean scope and cannot see it, so the script throws a reference error right away. Run it on the challenge page, where the data is already on the window object.
Learn more
The browser JavaScript console (accessible via F12 or Ctrl+Shift+I) is one of the most powerful tools in web security research. It provides a full JavaScript REPL (Read-Eval-Print Loop) running in the page's security context, meaning it has access to all the same objects the page's own scripts do.
The
alert()function creates a synchronous modal dialog - it pauses all JavaScript execution on the page until dismissed. While basic, alert-based output has been a debugging staple since early JavaScript. In security research,alert(1)is the canonical proof-of-concept payload for demonstrating Cross-Site Scripting (XSS) vulnerabilities because it's harmless but visually confirms code execution.For CTF challenges, the console is invaluable because you can inspect variables, call functions, and read properties that aren't exposed in the visible UI. Many web challenges hide flags in JavaScript variables, HTML attributes, or API responses that are only visible through the console or Network tab.
Interactive tools
- Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
- Regex TesterTest regular expressions against a string with live match highlighting, flag toggles, and common CTF pattern shortcuts.
Flag
Reveal flag
picoCTF{p@g3_turn3r_e8b...}
Running the bookmarklet reveals the alert containing the flag above.