LIT CTF 2026 Writeup: no way out

Final flag:
LITCTF{y0u_3sc4ped_th3_f0rm_6bq3}
The title, no way out, is the first hint: the important part is not just answering questions, but understanding how the form navigates between sections.
1. Testing the form
The first question asks:
What’s the first part of the flag?
I tried submitting:
LITCTF{The form replied:
nope, that’s wrong
That tells us the form is validating answers on the client side. Since this is Google Forms, the next step is to inspect what the browser already received.
2. Reading the form source
Using DevTools, search the page source for:
FB_PUBLIC_LOAD_DATA_This is Google Forms’ public form data. It contains much more than the visible questions:
- questions and choices;
- validation rules;
- section routes;
- hidden section text;
- the form’s navigation state.
The expected first answer is exposed in the validation data:
LITCTF{y0u_So the flag begins with:
LITCTF{y0u_The important lesson is simple:
Client-side validation is not secret. If the browser needs the expected answer, the expected answer is usually present somewhere in the page data.
The same source also exposes the hidden form state, including pageHistory.

3. Recovering 3sc4ped
After the first part, the form asks for the next letter several times. Each page presents many choices, but most choices route backward. Only one choice continues forward.
The routes in FB_PUBLIC_LOAD_DATA_ make this visible. Conceptually:
a -> old sectionb -> old sectionc -> old section3 -> next section4 -> old section...There is no need to brute-force the answer. Pick the choice whose destination differs from the old/backward section.
Repeating this process gives:
3 s c 4 p e dAt this point, the flag is:
LITCTF{y0u_3sc4pedThe same progress can also appear in the hidden partialResponse field after the answers are submitted.
4. The trap page
The form eventually shows:
You’re trapped here. You can still access the past, but not the future.
That message is the next hint.
Google Forms tracks visited sections with a hidden input:
<input type="hidden" name="pageHistory" value="0,1,2,3,4,5,6,7,8">pageHistory is not the flag. It is the list of pages that Google Forms believes we have already visited.
Because this state is client-side, we can edit it.
At the trap page, change:
0,1,2,3,4,5,6,7,8to:
0,1,2,3,4,5,6,7,8,9Then use the form’s back navigation. This lets us enter the first hidden future page, where the next fragment is revealed:
_th3_f0rm_After continuing forward, the form gives:
6bq3The last page contributes:
}
5. Why add only 9?
This is the key detail.
We do not need to write:
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14We only need to fake access to the first hidden future page. Once we enter that page, Google Forms continues its normal routing and updates pageHistory itself.
So:
0,1,2,3,4,5,6,7,8,9means:
Let me enter the first future page.
Adding many more page numbers manually can reveal decoy sections. More pages do not mean more correct flag characters.
The correct strategy is:
- use
FB_PUBLIC_LOAD_DATA_to understand the real routes; - use
pageHistoryto reach the hidden path; - let the form’s own navigation reveal the valid fragments.
6. Shortest solving script
Once the form structure is understood, the solve can be reduced to a small parser:
import re, json, requests
s = requests.get("https://forms.gle/kniocxKJN1RiDaTU7").textd = json.loads(re.search(r"FB_PUBLIC_LOAD_DATA_ = (.*?);", s, re.S)[1])[1][1]
flag = d[0][4][0][4][0][2][0]
for x in d: if (x[1] or "").startswith("What's the next letter"): flag += next(c[0] for c in x[4][0][1] if c[2] != 588010028)
sec = [0] + [i for i, x in enumerate(d) if x[3] == 8]
for i in (9, 16, 11, 20): flag += re.sub(r"Here's.*flag:\s*|\s+", "", d[sec[i]][2])
print(flag)Output:
LITCTF{y0u_3sc4ped_th3_f0rm_6bq3}Final flag
Combining the valid fragments:
LITCTF{y0u_3sc4ped_th3_f0rm_6bq3}gives:
LITCTF{y0u_3sc4ped_th3_f0rm_6bq3}Takeaway
The form says there is no way out, but the browser already has the map.
The solve uses three client-side observations:
FB_PUBLIC_LOAD_DATA_ -> form structure, answers, and routingpartialResponse -> saved answerspageHistory -> editable visited-page historyThe essential bypass is changing:
0,1,2,3,4,5,6,7,8to:
0,1,2,3,4,5,6,7,8,9That is enough to enter the hidden future path. From there, the form’s own routing leads to the remaining real flag fragments.
Share Article
If this article helped you, please share it with others!














