Skip to content

Commit a552db2

Browse files
committed
Enable autoescaping in report templates to prevent HTML injection
1 parent 4059782 commit a552db2

File tree

4 files changed

+48
-4
lines changed

4 files changed

+48
-4
lines changed

ax/utils/report/render.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import pkgutil
1111

1212
from ax.plot.render import _js_requires, _load_css_resource as _load_plot_css_resource
13-
from jinja2 import Environment, FunctionLoader
13+
from jinja2 import Environment, FunctionLoader, select_autoescape
1414

1515
REPORT_MODULE_NAME = "ax.utils.report"
1616

@@ -142,4 +142,7 @@ def _load_html_template(name: str) -> str:
142142

143143

144144
def _get_jinja_environment() -> Environment:
145-
return Environment(loader=FunctionLoader(_load_html_template))
145+
return Environment(
146+
loader=FunctionLoader(_load_html_template),
147+
autoescape=select_autoescape(["html", "xml"]),
148+
)

ax/utils/report/resources/simple_template.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
{% extends "base_template.html" %}
55
{% block content %}
66
{% for element in html_elements %}
7-
{{element}}
7+
{{element | safe }}
88
{% endfor %}
99
{% endblock %}

ax/utils/report/resources/sufficient_statistic.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<h2>{{cell.caption}}</h2>
1717
</div>
1818
<div class="cell_body">
19-
{{cell.html}}
19+
{{ cell.html | safe }}
2020
</div>
2121
{% endif %}
2222
{% endfor %}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python3
2+
import importlib.util
3+
import sys
4+
import types
5+
from pathlib import Path
6+
7+
ROOT = Path(__file__).resolve().parents[1] # repo root
8+
REPORT_RES = ROOT / "ax" / "utils" / "report" / "resources"
9+
10+
# ---- Stub ax.plot.render so render.py can import without importing full ax package ----
11+
ax_mod = types.ModuleType("ax")
12+
ax_plot_mod = types.ModuleType("ax.plot")
13+
ax_plot_render_mod = types.ModuleType("ax.plot.render")
14+
15+
ax_plot_render_mod._js_requires = lambda *a, **k: ""
16+
ax_plot_render_mod._load_css_resource = lambda *a, **k: ""
17+
18+
sys.modules["ax"] = ax_mod
19+
sys.modules["ax.plot"] = ax_plot_mod
20+
sys.modules["ax.plot.render"] = ax_plot_render_mod
21+
22+
# ---- Load ax/utils/report/render.py by file path ----
23+
render_path = (ROOT / "ax" / "utils" / "report" / "render.py").resolve()
24+
spec = importlib.util.spec_from_file_location("ax_utils_report_render", render_path)
25+
assert spec and spec.loader, "Failed to load module spec"
26+
mod = importlib.util.module_from_spec(spec)
27+
spec.loader.exec_module(mod)
28+
29+
# ---- Monkeypatch ALL pkgutil-based loaders so we don't need package resources ----
30+
mod._load_css_resource = lambda: ""
31+
mod._load_plot_css_resource = lambda: ""
32+
mod._load_html_template = lambda name: (REPORT_RES / name).read_text(encoding="utf-8")
33+
34+
# ---- Now test escaping ----
35+
payload = "<img src=x onerror=alert('AX_XSS_TEST')>"
36+
html = mod.render_report_elements(payload, [mod.p_html("hello")])
37+
38+
assert "<img" not in html, "FAIL: raw HTML injection still present"
39+
assert "&lt;img" in html, "FAIL: expected escaped payload not found"
40+
41+
print("[OK] experiment_name is escaped (autoescape enabled)")

0 commit comments

Comments
 (0)