Add check for Flask app debug=True usage
When executed with debug=True, Flask applications expose the Werkzeug debugger which includes an abritrary code execution function. This check looks for a combination of the flask module being imported, a .run() call, and a named argument debug=True. Setting it up in plugins/app_debug.py so we can add checks for Django and perhaps other frameworks in future. Change-Id: If49e53d0807dfc2fccad6433edc5ef43f5464f22 Implements: blueprint detect-werkzeug-debug-enabled
This commit is contained in:
parent
a0f39927ff
commit
517ab2f7ab
|
@ -0,0 +1,32 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
#
|
||||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import bandit
|
||||
from bandit.core.test_properties import checks
|
||||
|
||||
|
||||
@checks('Call')
|
||||
def flask_debug_true(context):
|
||||
if context.is_module_imported_like('flask'):
|
||||
if context.call_function_name_qual.endswith('.run'):
|
||||
if context.check_call_arg_value('debug', 'True'):
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text="A Flask app appears to be run with debug=True, "
|
||||
"which exposes the Werkzeug debugger and allows "
|
||||
"the execution of arbitrary code."
|
||||
)
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
flask_debug_true
|
||||
================
|
||||
|
||||
Description
|
||||
-----------
|
||||
Running Flask applications in debug mode results in the Werkzeug debugger
|
||||
being enabled. This includes a feature that allows arbitrary code execution.
|
||||
Documentation for both Flask [1]_ and Werkzeug [2]_ strongly suggests that
|
||||
debug mode should never be enabled on production systems.
|
||||
|
||||
Operating a production server with debug mode enabled was the probable cause
|
||||
of the Patreon breach in 2015 [3]_.
|
||||
|
||||
Available Since
|
||||
---------------
|
||||
- Bandit v0.15.0
|
||||
|
||||
Config Options
|
||||
--------------
|
||||
None
|
||||
|
||||
Sample Output
|
||||
-------------
|
||||
.. code-block:: none
|
||||
|
||||
>> Issue: A Flask app appears to be run with debug=True, which exposes
|
||||
the Werkzeug debugger and allows the execution of arbitrary code.
|
||||
Severity: High Confidence: High
|
||||
Location: examples/flask_debug.py:10
|
||||
9 #bad
|
||||
10 app.run(debug=True)
|
||||
11
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://flask.pocoo.org/docs/0.10/quickstart/#debug-mode
|
||||
.. [2] http://werkzeug.pocoo.org/docs/0.10/debug/
|
||||
.. [3] http://labs.detectify.com/post/130332638391/how-patreon-got-hacked-publicly-exposed-werkzeug
|
|
@ -0,0 +1,19 @@
|
|||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def main():
|
||||
raise
|
||||
|
||||
#bad
|
||||
app.run(debug=True)
|
||||
|
||||
#okay
|
||||
app.run()
|
||||
app.run(debug=False)
|
||||
|
||||
#unrelated
|
||||
run()
|
||||
run(debug=True)
|
||||
run(debug)
|
|
@ -31,6 +31,9 @@ bandit.formatters =
|
|||
xml = bandit.formatters.xml:report
|
||||
html = bandit.formatters.html:report
|
||||
bandit.plugins =
|
||||
# bandit/plugins/app_debug.py
|
||||
flask_debug_true = bandit.plugins.app_debug:flask_debug_true
|
||||
|
||||
# bandit/plugins/asserts.py
|
||||
assert_used = bandit.plugins.asserts:assert_used
|
||||
|
||||
|
|
|
@ -416,3 +416,10 @@ class FunctionalTests(testtools.TestCase):
|
|||
self.assertEqual(5, issues[1].lineno)
|
||||
self.assertEqual(list(range(3, 6+1)), issues[1].linerange)
|
||||
self.assertIn('shell=True', issues[1].get_code())
|
||||
|
||||
def test_flask_debug_true(self):
|
||||
expect = {
|
||||
'SEVERITY': {'HIGH': 1},
|
||||
'CONFIDENCE': {'MEDIUM': 1}
|
||||
}
|
||||
self.check_example('flask_debug.py', expect)
|
||||
|
|
Loading…
Reference in New Issue