Escalating debug mode in Django to RCE, SSRF, SQLi

Security implications of DEBUG=true in Django. Learnings from an ethical hacker's perspective

· 3 min read
Escalating debug mode in Django to RCE, SSRF, SQLi

Security implications of DEBUG=true in Django. Learnings from an ethical hacker's perspective. How to escalate it to higher severity 👇 (from low/medium to high/critical)

What is a debug mode in Django?

Debug mode in Django is a setting (DEBUG=True) that helps in the application development phase by providing detailed error pages when something goes wrong, but It's a security risk in a production environment and should be turned off 🥸

Security implications of DEBUG=true in Django app

An attacker will be able to:

  1. Extract all endpoints available on the server
  2. Leak secrets and credentials (most of the time)
  3. Escalate it to RCE, SSRF, SQLi

The detailed error page with stack trace + information about available endpoints is a superpower for ethical hackers. I used it several times and escalated it to SSRFs, RCEs, and credential leaks.

How to detect Debug mode in the Django app at scale?

You can use the module on the Vidoc platform:)

How to use this module:

  1. Create a free account on the Vidoc platform
  2. Start Recon on some domain and wait for the Recon to finish
  3. Go to Module and click "Execute Module"
Module “Django debug mode detection”
What is the “Django debug mode detection?“The “Django debug mode detection” module is designed to identify whether the debug mode is enabled in Django

Vidoc module

Let's look at extracting the list of endpoints first!

Listing endpoints in Django app

Example of error "Page not found" in Django

To do that we need to request an endpoint that does not exist in the application, for example:

- /doesnotexist 
- /api/doesnotexist 

When you open the page with the endpoint that does not exist you will be able to see all other endpoints! You can try going even deeper by looking at returned endpoints and adding doesnotexist to them.

In our case:

- /api/v1/doesnotexist
- /admin/doesnotexist

If you are lucky, the errors will return more endpoints:)

Leaking credentials in Django app

Example of RuntimeError page in Django

This is all about triggering RuntimeError. When the server encounters a "severe" error it will print the whole stack trace that will contain the settings of the server and potential secrets.

How to trigger RuntimeError in Django app?

1. Use the list of endpoints and try making a request with the wrong request method, wrong params, or wrong auth tokens
2. Make a POST request to /admin/1 endpoint

When you trigger the RuntimeError you should see a red page with a stack trace!

Where to find exposed secrets?

  • They can be found in the Settings section (at the bottom of the error page).
  • In newer versions of Django, secrets can also be leaked through "Local vars" of the stack trace (Django does not sanitize it)

Escalating to SQLi, SSRF, RCE

With the stack trace, you can gain insights into how the service works - you can leak parts of the code and use it to your advantage. You can check which endpoints are available without any for of authentication and use them for further research.


  1. Check which endpoints are avaliable without auth (if you have authentication for the service you can skip this step)
  2. Try sending requests to those endpoints with malformed requests - with SSRF, SQLi, RCE, or any other payloads
  3. If there is any indication that the endpoint might be vulnerable to SSRF, SQLi, or RCE - go deeper and use the stack trace to your advantage:)