python.flask.security.injection.csv-writer-injection.csv-writer-injection

Author
unknown
Download Count*
License
Detected user input into a generated CSV file using the built-in csv
module. If user data is used to generate the data in this file, it is possible that an attacker could inject a formula when the CSV is imported into a spreadsheet application that runs an attacker script, which could steal data from the importing user or, at worst, install malware on the user's computer. defusedcsv
is a drop-in replacement with the same API that will attempt to mitigate formula injection attempts. You can use defusedcsv
instead of csv
to safely generate CSVs.
Run Locally
Run in CI
Defintion
rules:
- id: csv-writer-injection
languages:
- python
message: Detected user input into a generated CSV file using the built-in `csv`
module. If user data is used to generate the data in this file, it is
possible that an attacker could inject a formula when the CSV is imported
into a spreadsheet application that runs an attacker script, which could
steal data from the importing user or, at worst, install malware on the
user's computer. `defusedcsv` is a drop-in replacement with the same API
that will attempt to mitigate formula injection attempts. You can use
`defusedcsv` instead of `csv` to safely generate CSVs.
metadata:
category: security
confidence: MEDIUM
cwe:
- "CWE-1236: Improper Neutralization of Formula Elements in a CSV File"
owasp:
- A01:2017 - Injection
- A03:2021 - Injection
references:
- https://github.com/raphaelm/defusedcsv
- https://owasp.org/www-community/attacks/CSV_Injection
- https://web.archive.org/web/20220516052229/https://www.contextis.com/us/blog/comma-separated-vulnerabilities
technology:
- python
- flask
subcategory:
- vuln
impact: MEDIUM
likelihood: MEDIUM
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
mode: taint
pattern-sinks:
- patterns:
- pattern-inside: |
$WRITER = csv.writer(...)
...
$WRITER.$WRITE(...)
- pattern: $WRITER.$WRITE(...)
- metavariable-regex:
metavariable: $WRITE
regex: ^(writerow|writerows|writeheader)$
pattern-sources:
- patterns:
- pattern-either:
- patterns:
- pattern-either:
- pattern: flask.request.form.get(...)
- pattern: flask.request.form[...]
- pattern: flask.request.args.get(...)
- pattern: flask.request.args[...]
- pattern: flask.request.values.get(...)
- pattern: flask.request.values[...]
- pattern: flask.request.cookies.get(...)
- pattern: flask.request.cookies[...]
- pattern: flask.request.stream
- pattern: flask.request.headers.get(...)
- pattern: flask.request.headers[...]
- pattern: flask.request.data
- pattern: flask.request.full_path
- pattern: flask.request.url
- pattern: flask.request.json
- pattern: flask.request.get_json()
- pattern: flask.request.view_args.get(...)
- pattern: flask.request.view_args[...]
- patterns:
- pattern: |
@$APP.route($ROUTE, ...)
def $FUNC(..., $ROUTEVAR, ...):
...
- focus-metavariable: $ROUTEVAR
severity: ERROR
Examples
csv-writer-injection.py
import csv
import flask
import io
from data import get_data
from util import chroot
app = flask.Flask(__name__)
@app.route("a/<title>")
def a(title):
stream = io.StringIO()
writer = csv.writer(stream)
data = get_data()
title_row = title + ("," * len(data[0]) - 1)
# ruleid: csv-writer-injection
writer.writerow(title_row)
writer.writerows(data)
stream.flush()
stream.seek(0)
return stream.read()
@app.route("ok")
def ok():
with open("data.csv") as fin:
# ok: csv-writer-injection
reader = csv.reader(fin)
lines = [line for line in reader]
return '\n'.join(lines)
Short Link: https://sg.run/JzqQ