GuardAPI Logo
GuardAPI

Fix Improper Error Handling in Tornado

Tornado's default error handling is a reconnaissance gift for attackers. By default, if an unhandled exception occurs or if 'debug=True' is set, the framework spills the entire stack trace, environment details, and library versions directly to the HTTP response. To harden a Tornado application, you must intercept the error lifecycle by overriding the 'write_error' method in your RequestHandler to ensure internal state never crosses the network boundary.

The Vulnerable Pattern

import tornado.ioloop
import tornado.web

class VulnerableHandler(tornado.web.RequestHandler): def get(self): # Logic error that triggers a traceback db_connection = None db_connection.execute(“SELECT * FROM users”)

def make_app(): # debug=True is often left on in production, leaking traces return tornado.web.Application([ (r”/vulnerable”, VulnerableHandler), ], debug=True)

The Secure Implementation

The vulnerability stems from the default implementation of 'write_error' in 'tornado.web.RequestHandler', which renders an HTML page containing the traceback if debugging is enabled or if not overridden. The fix involves three steps: 1. Create a 'BaseHandler' that overrides 'write_error'. 2. Use 'kwargs.get("exc_info")' to log the actual error details to a secure internal log file rather than the HTTP response. 3. Return a generic, sanitized JSON message to the client. Finally, ensure 'debug=False' is explicitly set in your production Application configuration to disable Tornado's built-in development tools.

import tornado.web
import logging
import json

class BaseHandler(tornado.web.RequestHandler): def write_error(self, status_code, **kwargs): """Sanitizes all error outputs to prevent Information Disclosure.""" self.set_header(‘Content-Type’, ‘application/json’)

    # Internal logging of the actual traceback for debugging
    if "exc_info" in kwargs:
        logging.error(f"Error: {kwargs['exc_info']}")

    # Standardized, non-leaky error response
    response = {
        "error": {
            "code": status_code,
            "message": "An internal server error occurred."
        }
    }

    if status_code == 404:
        response["error"]["message"] = "Resource not found."
    elif status_code == 403:
        response["error"]["message"] = "Access denied."

    self.finish(json.dumps(response))

class SecureHandler(BaseHandler): def get(self): # This crash will now return a clean JSON error, not a trace raise Exception(“Critical DB failure”)

System Alert • ID: 1485
Target: Tornado API
Potential Vulnerability

Your Tornado API might be exposed to Improper Error Handling

74% of Tornado apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

Free Tier • No Credit Card • Instant Report

Verified by Ghost Labs Security Team

This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.