Skip to content

Commit

Permalink
Sanitize exported CSVs to avoid CSV injection.
Browse files Browse the repository at this point in the history
  • Loading branch information
rtibbles committed Jun 20, 2022
1 parent 015e294 commit 95609c1
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 0 deletions.
2 changes: 2 additions & 0 deletions kolibri/core/auth/csv_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from kolibri.core.auth.models import FacilityUser
from kolibri.core.query import SQCount
from kolibri.core.utils.csv import open_csv_for_writing
from kolibri.core.utils.csv import sanitize


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -103,6 +104,7 @@ def map_output(obj):
mapped_obj[label] = output_mappings[header](obj)
elif header in obj:
mapped_obj[label] = obj[header]
mapped_obj[label] = sanitize(mapped_obj[label])
return mapped_obj


Expand Down
2 changes: 2 additions & 0 deletions kolibri/core/auth/management/commands/bulkexportusers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from kolibri.core.tasks.management.commands.base import AsyncCommand
from kolibri.core.tasks.utils import get_current_job
from kolibri.core.utils.csv import open_csv_for_writing
from kolibri.core.utils.csv import sanitize
from kolibri.utils import conf

try:
Expand Down Expand Up @@ -114,6 +115,7 @@ def map_output(obj):
mapped_obj[label] = output_mappings[header](obj)
elif header in obj:
mapped_obj[label] = obj[header]
mapped_obj[label] = sanitize(mapped_obj[label])
return mapped_obj


Expand Down
2 changes: 2 additions & 0 deletions kolibri/core/logger/csv_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from kolibri.core.content.models import ChannelMetadata
from kolibri.core.content.models import ContentNode
from kolibri.core.utils.csv import open_csv_for_writing
from kolibri.core.utils.csv import sanitize
from kolibri.utils import conf


Expand Down Expand Up @@ -94,6 +95,7 @@ def map_object(obj):
mapped_obj[label] = mappings[header](obj)
elif header in obj:
mapped_obj[label] = obj[header]
mapped_obj[label] = sanitize(mapped_obj[label])
return mapped_obj


Expand Down
21 changes: 21 additions & 0 deletions kolibri/core/utils/csv.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import io
import re
import sys
from numbers import Number


def open_csv_for_writing(filepath):
Expand All @@ -12,3 +14,22 @@ def open_csv_for_reading(filepath):
if sys.version_info[0] < 3:
return io.open(filepath, "rb")
return io.open(filepath, "r", newline="", encoding="utf-8-sig")


negative_number_regex = re.compile("^-?[0-9,\\.]+$")
csv_injection_chars = {"@", "+", "-", "=", "|", "%"}


def sanitize(value):
if value is None or isinstance(value, Number):
return value

value = str(value)
if (
value
and value[0] in csv_injection_chars
and not negative_number_regex.match(value)
):
value = value.replace("|", "\\|")
value = "'" + value
return value

0 comments on commit 95609c1

Please sign in to comment.