I'm trying to write a stored xss vulnerable flask web app. My app receive input via this input field <input type="text" name="content" id="content" />
and then show User input into an HTML table.
I tried to insert a script like <script>alert(1)</script>
into the input field but when it is shown, the script isn't triggered.
Here is my code:
app.py
from flask import Flask, render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app)
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(200), nullable=False)
date_created = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return '<Task %r>' % self.id
@app.route('/', methods = ['POST', 'GET'])
def index():
if request.method == 'POST':
task_content = request.form['content']
new_task = Todo(content=task_content)
try:
db.session.add(new_task)
db.session.commit()
return redirect('/')
except:
return "There was an issue adding your task"
else:
tasks = Todo.query.order_by(Todo.date_created).all()
return render_template("index.html", tasks=tasks)
if __name__ == "__main__":
app.run(debug=True)
index.html
{% extends 'base.html' %}
{% block head %}
<title>Task Master</title>
{% endblock %}
{% block body %}
<div class="content">
<h1 style="text-align: center">Task Master</h1>
{% if tasks|length < 1 %}
<h4 style="text-align: center">There are no tasks. Create one below!</h4>
{% else %}
<table>
<tr>
<th>Task</th>
<th>Added</th>
<th>Actions</th>
</tr>
{% for task in tasks %}
<tr>
<td>{{ task.content }}</td>
<td>{{ task.date_created.date() }}</td>
<td>
<a href="/delete/{{task.id}}">Delete</a>
<br />
<a href="/update/{{task.id}}">Update</a>
</td>
</tr>
{% endfor %}
</table>
{% endif %}
<div class="form">
<form action="/" method="POST">
<input type="text" name="content" id="content" />
<input type="submit" value="Add Task" />
</form>
</div>
</div>
{% endblock %}
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" >
<meta http-equiv="X-UA-Compatible" content="IE=edge" >
<meta name="viewport" content="width=device-width, initial-scale=1.0" >
<link
rel="stylesheet"
href="{{ url_for('static', filename='css/main.css') }}"
>
{% block head %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
I follow this example.
This is a screen of the form:
(https://i.sstatic.net/870tY.png)
and this is a screen of the HTML after the script submission:
(https://i.sstatic.net/U1Jdd.png)
How do I make the script executable when the page is loaded?
Flask uses Jinja2 template engine and Flask enables automatic escaping on Jinja2 by default.
If you really want to allow XSS, change {{ task.content }}
to {{ task.content|safe }}
on your template.
More information: https://flask.palletsprojects.com/en/1.1.x/templating/#controlling-autoescaping