Skip to main content

Free 30-min security demo Book Now

Academy Debug Mode in Production
Beginner · 15 min

Debug Mode in Production

Learn how debug mode exposes stack traces, environment variables, and internal paths to attackers.

1 Debug Mode Information Disclosure

Debug mode in web frameworks provides detailed error information to help developers troubleshoot. In production, this information is invaluable to attackers.

Django DEBUG=True leak:

# When DEBUG=True and an error occurs, Django exposes:
# - Full Python stack trace with local variable values
# - All settings (including SECRET_KEY, DATABASE, API keys)
# - File paths on the server
# - SQL queries that caused errors
# - Environment variables

Flask debug mode:

app.run(debug=True)  # Exposes Werkzeug debugger
# Attackers can access an interactive Python console!
# Complete server compromise if Werkzeug debugger is accessible

Express.js in development mode:

app.use((err, req, res, next) => {
  res.status(500).send(err.stack);  // Stack trace to all users!
});

Even if debug mode is not explicitly enabled, error handlers that return stack traces or internal paths create the same information disclosure risk.

2 Environment-Based Configuration

Use environment variables to toggle debug mode, and ensure production uses safe error handlers that log details internally but return generic messages to users.

Django settings.py:

import os

# Never hardcode DEBUG=True
DEBUG = os.environ.get("DJANGO_DEBUG", "False") == "True"

# Production checklist — Django will warn if these are wrong
if not DEBUG:
    ALLOWED_HOSTS = os.environ["ALLOWED_HOSTS"].split(",")
    SECRET_KEY = os.environ["SECRET_KEY"]  # No default!

Express.js production error handler:

const isDev = process.env.NODE_ENV !== "production";

// Development — detailed errors
if (isDev) {
  app.use((err, req, res, next) => {
    res.status(500).json({ error: err.message, stack: err.stack });
  });
} else {
  // Production — generic error, log internally
  app.use((err, req, res, next) => {
    logger.error({ err });  // Detailed logging to server logs only
    res.status(500).json({ error: "Internal server error" });
  });
}

Knowledge Check

0/3 correct
Q1

What information does Django expose when DEBUG=True and an unhandled exception occurs?

Q2

What special risk does Flask's debug=True create beyond information disclosure?

Q3

What is the correct production behavior for unhandled exceptions?

Code Exercise

Environment-Based Error Handler

The error handler always returns the full stack trace. Fix it to only include technical details in development, returning a generic message in production.

javascript

Put it into practice

Find Debug Mode in Production in your own code

Offensive360 SAST traces the tainted data flow behind this class of bug across 60+ languages and ships a secure fix with every finding. Public open-source projects scan free; teams can see it on their own repository in a 30-minute demo.