Harden HTML output against U+2028 XSS + two crash-on-adversarial-input fixes (#1357)

Harden HTML export against U+2028/U+2029 script-breakout XSS + two crash-on-adversarial-input fixes (non-dict LLM JSON, _extract_parallel IndexError). Validated: full suite 2107 passed, HTML export smoke clean. Thanks @mistic96.
This commit is contained in:
mistic96
2026-06-17 10:46:19 +01:00
committed by GitHub
parent fd463deb03
commit d8fa70e17b
3 changed files with 15 additions and 6 deletions
+4 -3
View File
@@ -12164,16 +12164,17 @@ def _extract_parallel(
try:
with concurrent.futures.ProcessPoolExecutor(max_workers=max_workers) as pool:
futures = {
pool.submit(_extract_single_file, item): item[0] for item in work_items
pool.submit(_extract_single_file, item): pos
for pos, item in enumerate(work_items)
}
for future in concurrent.futures.as_completed(futures):
try:
idx, result = future.result()
per_file[idx] = result
except Exception as exc:
idx = futures[future]
pos = futures[future]
print(
f" warning: worker failed for {work_items[idx][1]}: {exc}",
f" warning: worker failed for {work_items[pos][1]}: {exc}",
file=sys.stderr, flush=True,
)
done_count += 1
+10 -2
View File
@@ -721,7 +721,12 @@ def _parse_llm_json(raw: str) -> dict:
else:
stripped = after_fence.strip()
try:
return json.loads(stripped)
parsed = json.loads(stripped)
if isinstance(parsed, dict):
return parsed
# Top-level array/scalar (common LLM output) is not a usable graph
# fragment; fall through to the next strategy rather than returning a
# non-dict that callers will try to subscript (e.g. result["input_tokens"]).
except json.JSONDecodeError:
pass
# Strategy 2: extract the first balanced JSON object found anywhere in
@@ -751,7 +756,10 @@ def _parse_llm_json(raw: str) -> dict:
depth -= 1
if depth == 0:
try:
return json.loads(stripped[start : i + 1])
parsed = json.loads(stripped[start : i + 1])
if isinstance(parsed, dict):
return parsed
break
except json.JSONDecodeError:
break
print(
+1 -1
View File
@@ -549,7 +549,7 @@ def emit_html(
) -> str:
# Escape </script> sequences so embedded JSON cannot break out of the
# <script> tag, and HTML-escape values that land in <title>/<h1>.
data_json = json.dumps(tree, ensure_ascii=False, separators=(",", ":")).replace("</", "<\\/")
data_json = json.dumps(tree, ensure_ascii=True, separators=(",", ":")).replace("</", "<\\/")
return _HTML_TEMPLATE.format(
title=_html.escape(title),
header=_html.escape(header),