Skip to content

Commit

Permalink
[AIRFLOW-1047] Sanitize strings passed to Markup
Browse files Browse the repository at this point in the history
We add the Apache-licensed bleach library and use
it to sanitize html
passed to Markup (which is supposed to be already
escaped). This avoids
some XSS issues with unsanitized user input being
displayed.

Closes apache#2193 from saguziel/aguziel-xss
  • Loading branch information
saguziel authored and bolkedebruin committed Mar 28, 2017
1 parent d8c0f59 commit fe9ebe3
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 8 deletions.
18 changes: 11 additions & 7 deletions airflow/www/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import dateutil.parser
import copy
import json
import bleach

import inspect
from textwrap import dedent
Expand Down Expand Up @@ -102,11 +103,12 @@


def dag_link(v, c, m, p):
dag_id = bleach.clean(m.dag_id)
url = url_for(
'airflow.graph',
dag_id=m.dag_id)
dag_id=dag_id)
return Markup(
'<a href="{url}">{m.dag_id}</a>'.format(**locals()))
'<a href="{}">{}</a>'.format(url, dag_id))


def log_url_formatter(v, c, m, p):
Expand All @@ -117,20 +119,22 @@ def log_url_formatter(v, c, m, p):


def task_instance_link(v, c, m, p):
dag_id = bleach.clean(m.dag_id)
task_id = bleach.clean(m.task_id)
url = url_for(
'airflow.task',
dag_id=m.dag_id,
task_id=m.task_id,
dag_id=dag_id,
task_id=task_id,
execution_date=m.execution_date.isoformat())
url_root = url_for(
'airflow.graph',
dag_id=m.dag_id,
root=m.task_id,
dag_id=dag_id,
root=task_id,
execution_date=m.execution_date.isoformat())
return Markup(
"""
<span style="white-space: nowrap;">
<a href="{url}">{m.task_id}</a>
<a href="{url}">{task_id}</a>
<a href="{url_root}" title="Filter on this task and upstream">
<span class="glyphicon glyphicon-filter" style="margin-left: 0px;"
aria-hidden="true"></span>
Expand Down
1 change: 1 addition & 0 deletions scripts/ci/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
alembic
bcrypt
bleach
boto
celery
cgroupspy
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ def do_setup():
scripts=['airflow/bin/airflow'],
install_requires=[
'alembic>=0.8.3, <0.9',
'bleach==2.0.0',
'configparser>=3.5.0, <3.6.0',
'croniter>=0.3.8, <0.4',
'dill>=0.2.2, <0.3',
Expand Down
12 changes: 11 additions & 1 deletion tests/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from __future__ import print_function

import bleach
import doctest
import json
import os
Expand Down Expand Up @@ -1423,7 +1424,7 @@ def test_variables(self):
os.remove('variables1.json')
os.remove('variables2.json')

class CSRFTests(unittest.TestCase):
class SecurityTests(unittest.TestCase):
def setUp(self):
configuration.load_test_config()
configuration.conf.set("webserver", "authenticate", "False")
Expand Down Expand Up @@ -1458,6 +1459,15 @@ def test_csrf_acceptance(self):
response = self.app.post("/admin/queryview/", data=dict(csrf_token=csrf))
self.assertEqual(200, response.status_code)

def test_xss(self):
try:
self.app.get("/admin/airflow/tree?dag_id=<script>alert(123456)</script>")
except:
# exception is expected here since dag doesnt exist
pass
response = self.app.get("/admin/log", follow_redirects=True)
self.assertIn(bleach.clean("<script>alert(123456)</script>"), response.data.decode('UTF-8'))

def tearDown(self):
configuration.conf.set("webserver", "expose_config", "False")
self.dag_bash.clear(start_date=DEFAULT_DATE, end_date=datetime.now())
Expand Down

0 comments on commit fe9ebe3

Please sign in to comment.