Broken Function Level Authorization

Broken Function Level Authorization with Flask [Mar 2026] [CVE-2015-5306]

[Updated Mar 2026] Updated CVE-2015-5306

Overview

OpenStack Ironic Inspector (ironic-inspector / ironic-discoverd) exposed a vulnerability described as CVE-2015-5306 where a Flask-based console could be accessed remotely if the app was run in debug mode. When the Flask/Werkzeug debugger is enabled, an attacker may trigger an error and drop into an interactive Python shell on the server, potentially allowing arbitrary code execution. This risk falls under CWE-254, External Control of System or Configuration Data, since the attacker can influence runtime behavior by enabling or exploiting the debug console through misconfiguration. Exploitation typically involves crafting a request that causes a failure in a Flask route while the application is in debug mode. The Werkzeug debugger presents an interactive console in the browser, which an unauthenticated or poorly authenticated remote user can use to execute Python on the host. Although CVE-2015-5306 targeted ironic-inspector, the underlying flaw is general: exposing the Flask debugger on public endpoints. Any Flask app that preserves debug mode in production or exposes error traces can be similarly compromised. Remediation in Flask involves preventing the production deployment from enabling the interactive debugger. Do not run Flask with debug=True in production, deploy behind a production WSGI server (gunicorn/uWSGI) or a reverse proxy, and implement proper error handling that does not leak stack traces or debugger consoles. Enforce environment-based configuration (FLASK_ENV=production), keep dependencies up to date, and add authentication and access controls around sensitive endpoints to reduce the blast radius of any errors that occur. The code example below shows a side-by-side vulnerable pattern and its fixed counterpart to illustrate the practical differences. The vulnerable variant runs with debug mode enabled and may reveal the Werkzeug debugger on errors, while the fixed variant disables debug mode and relies on standard error handling without exposing the debugger.

Code Fix Example

Flask API Security Remediation
--- VULNERABLE PATTERN ---
from flask import Flask
import os

def create_vuln_app():
    app = Flask(__name__)
    # Vulnerable: debug mode enabled in production
    app.config['DEBUG'] = True

    @app.route('/trigger')
    def vuln_trigger():
        # This error will drop into Werkzeug debugger if DEBUG is True
        return 1/0

    return app

--- FIXED PATTERN ---

def create_fixed_app():
    app = Flask(__name__)
    # Production-safe: disable debug mode
    app.config['DEBUG'] = False

    @app.route('/trigger')
    def fixed_trigger():
        # Error will be handled by default error page without debugger
        return 1/0

    return app

if __name__ == '__main__':
    mode = os.environ.get('APP_MODE', 'vuln')
    if mode == 'fix':
        app = create_fixed_app()
        app.run(host='0.0.0.0', port=5000, debug=False)
    else:
        app = create_vuln_app()
        app.run(host='0.0.0.0', port=5000, debug=True)

CVE References

Choose which optional cookies to allow. You can change this any time.