DEV Community

CTFDojo
CTFDojo

Posted on Originally published at ctfdojo.com

PicoCTF Insp3ct0r Writeup — Find a Flag Hidden in HTML, JS & CSS

The flag is split into 3 pieces hidden in comments: one in the page's HTML, one in the linked .js file, one in the linked .css file. Just inspect each one to reconstruct the full flag.

  • Platform: picoGym
  • Category: Web Exploitation
  • Points: 100 pts
  • Difficulty: Beginner
  • Technique: Reading source code / DevTools

Challenge description

The challenge simply gives a URL to a website with no other hint:

"There is a flag in this html, but the button doesn't work? http://mercury.picoctf.net:PORT/"

Arriving on the page, we find a minimalist site: a title, a bit of text, and a button that doesn't seem to do anything when clicked. Nothing displayed on screen looks like a flag. The challenge's name — Insp3ct0r — is a fairly clear hint: we're going to need to inspect what's hiding behind the page rather than what it displays.

Step 1 — Read the HTML source code

First reflex on any web challenge: look at the page's source code with Ctrl+U (or right-click → "View page source"). We deliberately avoid opening DevTools directly here, because the element inspector shows the DOM after JS modifications, whereas "View source" shows the raw HTML as sent by the server — exactly what we want to look for forgotten comments.

Scanning through the file, we come across an HTML comment in the middle of the document:

<!-- part 1: picoCTF{*********** -->
<button onclick="myFunction()">Click Me</button>
Enter fullscreen mode Exit fullscreen mode

First piece of the flag found, tucked away in a comment nobody was supposed to leave in production.

Step 2 — Explore the linked JavaScript file

Still in the HTML source code, we spot the tag that loads an external script, either in the <head> or just before the closing <body> tag:

<script src="js/main.js"></script>
Enter fullscreen mode Exit fullscreen mode

Many beginners stop at the HTML and completely miss the referenced files. Yet all it takes is opening this URL directly in the browser (or via curl) to read the JS file in plain text:

$ curl -s http://mercury.picoctf.net:PORT/js/main.js
Enter fullscreen mode Exit fullscreen mode
function myFunction() {
  // part 2: ***********
  alert("This button doesn't do anything");
}
Enter fullscreen mode Exit fullscreen mode

Second piece found, this time in a JavaScript comment — and along the way, we understand why the button "doesn't do anything": it just triggers a useless alert, a decoy to distract attention.

Step 3 — Explore the CSS stylesheet

Same logic for the stylesheet, also referenced in the <head>:

<link rel="stylesheet" href="css/style.css">
Enter fullscreen mode Exit fullscreen mode

We open it directly:

$ curl -s http://mercury.picoctf.net:PORT/css/style.css
Enter fullscreen mode Exit fullscreen mode
body {
  font-family: sans-serif;
  background-color: #fdfdfd;
}

/* part 3: ***********}  */
button {
  padding: 10px 20px;
}
Enter fullscreen mode Exit fullscreen mode

Third and final piece, hidden in a CSS comment.

Step 4 — Reconstruct the flag

All that's left is to string the three pieces together in the order they were found (HTML → JS → CSS):

part 1 (HTML): picoCTF{***********
part 2 (JS)  : ***********
part 3 (CSS) : ***********}

picoCTF{***************************}
Enter fullscreen mode Exit fullscreen mode

Step 5 — Bonus: automate with curl + grep

On a challenge with more files to explore, we can save time by scanning several resources at once to spot all the suspicious comments:

$ for f in index.html js/main.js css/style.css; do
    echo "=== $f ==="
    curl -s "http://mercury.picoctf.net:PORT/$f" | grep -E "<!--|//|/\*"
done
Enter fullscreen mode Exit fullscreen mode
=== index.html ===
<!-- part 1: picoCTF{*********** -->
=== js/main.js ===
  // part 2: ***********
=== css/style.css ===
/* part 3: ***********}  */
Enter fullscreen mode Exit fullscreen mode

A single command, and the three pieces come right out — handy as soon as the number of files to check grows.

🚩 picoCTF{ flag intentionally hidden }

The flag is deliberately hidden — follow the method, you've earned it. 💪

Key takeaways

This challenge is a perfect introduction to an essential web security reflex: everything sent to the browser is readable by the user, whether it's HTML, JavaScript, or CSS. A development comment left in production can leak sensitive information — credentials, internal paths, business logic, or even an entire flag.

  • Always inspect ALL resources loaded by a page (JS, CSS, images), not just the HTML — development comments often end up in production
  • "View source" (Ctrl+U) shows the raw HTML from the server, while the DOM inspector shows the state after JS execution — the two are complementary
  • Automating the search for comments with curl + grep saves precious time on challenges with multiple files

Originally published on CTFdojo — join the CTFdojo Discord to discuss writeups and get notified about new ones.

Top comments (0)