eval() in Elasticsearch Result DeserializationThe Elasticsearch backend in django-haystack calls eval() on raw field values returned from Elasticsearch when a SearchField is declared with an index_fieldname alias that differs from the logical field name. During result processing, the backend looks up fields by logical name but Elasticsearch stores them under the alias key; the lookup fails and the value falls through to _to_python() → eval(). An attacker who can control content that is indexed into Elasticsearch—and can trigger or wait for a search that returns it—achieves arbitrary code execution in the Django application process. CVSS 3.1 Base Score: 8.5 (High).
Sink — haystack/backends/elasticsearch_backend.py:865:
converted_value = eval(value)
_to_python() (line ~850) attempts to parse a string value by calling eval() before performing any type-safety check. If the value is an attacker-controlled Python expression such as __import__('os').system(...), the expression is executed unconditionally.
Root cause — haystack/backends/elasticsearch_backend.py:727–737:
for key, value in source.items():
string_key = str(key)
if string_key in index.fields and hasattr(index.fields[string_key], "convert"):
additional_fields[string_key] = index.fields[string_key].convert(value)
else:
additional_fields[string_key] = self._to_python(value)
index.fields is keyed by the logical field name (e.g. "name"), but Elasticsearch stores the document under the index_fieldname alias (e.g. "name_s"). Because "name_s" not in index.fields, the branch falls through to self._to_python(value).
Data flow (source → sink):
haystack/indexes.py:226 — self.prepared_data[field.index_fieldname] = field.prepare(obj) stores data under the alias.haystack/backends/elasticsearch_backend.py:218 — prepared data copied into...3.4.0Exploitability
AV:NAC:LAT:NPR:LUI:NVulnerable System
VC:HVI:HVA:HSubsequent System
SC:NSI:NSA:N8.7/CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N