Sitemap
Ryca

Ryca

Top 1% on TryHackMe. Curious learner exploring cybersecurity from offense to defense.

Web Frameworks: Python |TryHackMe

4 min readJul 20, 2026

--

Review Django and Flask source for framework-specific sinks, then exploit each on the lab machine.

Press enter or click to view image in full size

Learning Objectives

  • Read Django and Flask source to locate framework-specific sinks
  • Recover a Django SECRET_KEY from a DEBUG=True 500 error page
  • Spot and exploit an ORM SQL injection that survives Django’s parameterisation
  • Decode and forge a Flask signed session cookie
  • Detect and exploit Jinja2 server-side template injection to reach command execution
  • Chain a reused secret across services to reach the highest privilege tier

Prerequisites

  • Working knowledge of HTTP and the request/response cycle
  • Familiarity with the OWASP Top 10
  • Comfort reading Python (no writing required) and using curl from a terminal

Answer the questions below

  • Which value in settings.py, when left True in production, makes Django render its detailed technical 500 error page?

DEBUG

  • Recover it once and you can forge any value Django signs: session cookies, CSRF tokens, and reset tokens. Which setting holds this root signing secret?

SECRET_KEY

  • Trigger the technical 500 page on the lab machine and read the leaked value. What is the SECRET_KEY? (Answer Format: the full value, including the prefix)

django-insecure-7h3_5h4r3d_fr4m3w0rk_k3y_2026

  • Of the three ORM escape hatches, which QuerySet method splices a raw SQL fragment into the WHERE clause and reintroduces SQL injection when input is f-stringed in instead of parameterised?

extra

  • Which keyword argument on that method binds the values through the database driver and removes the injection?

params

  • Read the model source to learn the schema, then inject through the live endpoint to read the hidden flag. What is the flag?

THM{dj4ng0_3xtr4_0rm_sql1}

  • A Flask session cookie is signed, not encrypted, so its integrity rests entirely on one secret. Which secret signs it, the same value shared with Django?

SECRET_KEY

  • Once the key is known, which command-line tool forges a valid Flask session cookie (and can also decode one or brute-force a weak key)?

flask-unsign

  • Forge a session with role set to admin, replace your cookie, and reach the dashboard. What is the flag?

THM{fl45k_s3ss10n_f0rg3d}

  • Unlike render_template, which treats its arguments as data, which Flask function compiles its string argument as a Jinja2 template on every call, making it the SSTI sink when fed user input?

render_template_string

  • The smoke test {{7*7}} returns 49 in both Jinja2 and Twig. Sending {{7*'7'}} tells them apart. What does it return in a Jinja2 context, confirming you are in Python rather than Twig?

7777777

  • Exploit the SSTI on /search to run a command and read /flag.txt. What is the flag?

THM{j1nj4_55t1_rc3_ch41n}

  • The key leaks from Django, yet the sessions you forge to reach the dashboard and console belong to the other service that trusts the same key. Which framework serves those two routes? (one word)

Flask

  • The chain starts by leaking the shared SECRET_KEY. Which Django route deliberately raises an exception, rendering the technical 500 page that echoes the key? (Answer Format: URL path with trailing slash)

/error/

  • Forge a superadmin session and reach /console. What is the final flag?

THM{py_fr4m3w0rk_ch41n_pwn3d}

Get Ryca’s stories in your inbox

Join Medium for free to get updates from this writer.

CONCLUSION

We reviewed two Python web applications the way a security tester does, by reading the source for the sink and then proving it on the running lab machine. The bugs were not exotic. Each one came from a framework default or a developer habit that is easy to ship and hard to spot from the outside.

What we walked away with:

  • DEBUG = True in production turns any unhandled exception into a dump of the application's configuration, and an echoed setting puts the SECRET_KEY itself on the page.
  • The Django ORM parameterises queries and stays safe until a developer reaches for .extra(), .raw(), or cursor.execute() with input formatted into the string.
  • A signed cookie is not an encrypted one, so we can read a Flask session, recover the key, and forge it at will.
  • render_template_string on user input is SSTI, and Jinja2 SSTI reaches RCE by walking Python's object graph to the os module.
  • A reused secret turns one leak into compromise of every service that trusts it, which is how the Django key in Task 2 gave us the Flask console in Task 6.

The thread running through all of it is the white-box angle. Half the work was reading the source to find the sink, and the other half was proving it on the live application. Once we know what each framework signs, trusts, and renders, the same patterns are quick to find in any codebase that uses them.

The review method itself, the read, map, trace, triage, and verify workflow, is covered in Web Frameworks: Code Review. The sibling entries carry these patterns into other stacks: Web Frameworks: Java (Spring Boot) is already available, and Web Frameworks: .NET (ASP.NET) covers the same bug classes with different syntax and different defaults.

--

--

Ryca
Ryca

Top 1% on TryHackMe. Curious learner exploring cybersecurity from offense to defense.