dont-use-client-side picoCTF 2019 Solution

Published: April 2, 2026

Description

Can you find the flag? It is hidden in the HTML source of this page.

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    View the page source
    Observation
    I noticed the challenge description says the flag is hidden in the HTML source, which suggested that the validation logic was written in client-side JavaScript rather than processed server-side, making View Page Source the right first move.
    Open the challenge URL. Press Ctrl+U (or right-click > View Page Source) to see the raw HTML. Look for a script tag containing the password validation logic.
    What didn't work first

    Tried: Opening the Elements panel in DevTools instead of View Page Source.

    The Elements panel shows the live DOM after JavaScript has run and the browser has parsed the page, not the raw HTML sent by the server. View Page Source (Ctrl+U) shows the actual downloaded HTML including all script tags with their original content, which is what you need to read the validation logic.

    Tried: Searching for the flag text directly in the source with Ctrl+F for 'picoCTF'.

    The flag is not printed as a literal string in the HTML - it is assembled from parts inside the JavaScript validation logic. You need to read and understand the script tag contents to find the substring comparisons and reconstruct the flag from them.

    Learn more

    When a web application validates a password purely in client-side JavaScript, the correct password must exist somewhere in the code the browser downloads. There is no server-side check to hide the secret.

  2. Step 2
    Find and concatenate the flag parts
    Observation
    I noticed the JavaScript source used a series of .substring() calls each comparing a fixed-length slice of the input to a hardcoded string, which suggested the flag was split into positional chunks that could be reassembled by sorting the expected values by their start index.
    The JavaScript validation function splits the input into 4-character chunks using .substring() and compares each chunk to a hardcoded value. Find each expected value in the source code and concatenate them in positional order to form the complete flag.
    What didn't work first

    Tried: Typing random guesses into the password form and watching the JavaScript alert to confirm.

    This treats the challenge as a guessing game rather than a code-reading exercise. The validation logic is fully visible in the source - there is no reason to guess. Reading the substring comparisons directly gives you the exact expected values for each position without any trial and error.

    Tried: Concatenating the hardcoded strings in the order they appear in the source file rather than by their positional arguments.

    The substring() calls may not appear in the source in the same order as their start positions. Each call specifies a start and end index - you must sort the expected values by their starting index to reconstruct the flag in the correct order. Concatenating them in source-file order can produce a garbled result.

    Learn more

    Look for lines like: checkpass.substring(0, split) == 'pico', checkpass.substring(split, split*2) == 'CTF{', etc. The variable split is typically 4, so each check covers a 4-character slice. Concatenate all the expected values in order of their start position.

    This challenge is the easiest demonstration that client-side validation provides zero real security - a user never even needs to type anything into the form; they just read the source.

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{no_clients_plz_...}

The password is validated by substring position checks in the JavaScript source. Concatenate all the expected 4-character substrings in positional order to reconstruct the flag.

Key takeaway

Any secret embedded in JavaScript that runs in the browser is public. The browser must download all the code needed to run a page, so hardcoded passwords, API keys, and validation logic are trivially visible to anyone who opens DevTools or views source. Real authentication always requires a server-side check where the secret never leaves the server. This is why storing credentials in front-end code is flagged as a critical finding in every web security assessment.

Related reading

Want more picoCTF 2019 writeups?

Useful tools for Web Exploitation

What to try next