|
8 | 8 | """ |
9 | 9 | import difflib |
10 | 10 | import functools |
| 11 | +import re |
11 | 12 | from collections import Counter, OrderedDict, namedtuple |
12 | 13 | from collections.abc import Iterator, Mapping |
13 | 14 | from itertools import chain, count, product |
|
40 | 41 |
|
41 | 42 | __all__ = ['Query', 'RawQuery'] |
42 | 43 |
|
| 44 | +# Quotation marks ('"`[]), whitespace characters, semicolons, or inline |
| 45 | +# SQL comments are forbidden in column aliases. |
| 46 | +FORBIDDEN_ALIAS_PATTERN = re.compile(r"['`\"\]\[;\s]|--|/\*|\*/") |
| 47 | + |
43 | 48 |
|
44 | 49 | def get_field_names_from_opts(opts): |
45 | 50 | return set(chain.from_iterable( |
@@ -994,8 +999,16 @@ def join_parent_model(self, opts, model, alias, seen): |
994 | 999 | alias = seen[int_model] = join_info.joins[-1] |
995 | 1000 | return alias or seen[None] |
996 | 1001 |
|
| 1002 | + def check_alias(self, alias): |
| 1003 | + if FORBIDDEN_ALIAS_PATTERN.search(alias): |
| 1004 | + raise ValueError( |
| 1005 | + "Column aliases cannot contain whitespace characters, quotation marks, " |
| 1006 | + "semicolons, or SQL comments." |
| 1007 | + ) |
| 1008 | + |
997 | 1009 | def add_annotation(self, annotation, alias, is_summary=False): |
998 | 1010 | """Add a single annotation expression to the Query.""" |
| 1011 | + self.check_alias(alias) |
999 | 1012 | annotation = annotation.resolve_expression(self, allow_joins=True, reuse=None, |
1000 | 1013 | summarize=is_summary) |
1001 | 1014 | self.append_annotation_mask([alias]) |
@@ -1873,6 +1886,7 @@ def add_extra(self, select, select_params, where, params, tables, order_by): |
1873 | 1886 | else: |
1874 | 1887 | param_iter = iter([]) |
1875 | 1888 | for name, entry in select.items(): |
| 1889 | + self.check_alias(name) |
1876 | 1890 | entry = str(entry) |
1877 | 1891 | entry_params = [] |
1878 | 1892 | pos = entry.find("%s") |
|
0 commit comments