From 080d6cc16647222278c0301911412dae77f85a94 Mon Sep 17 00:00:00 2001
From: Paula Ruiz-Rodriguez <50167687+Paururo@users.noreply.github.com>
Date: Sun, 18 Oct 2026 10:46:08 +0200
Subject: [PATCH] fix: build the policy sentence from text nodes, not markup
The website's policy picker pasted the policy name it read from the page into innerHTML, which CodeQL flags as DOM text reinterpreted as HTML. The sentence is now built from text nodes, so any name shows as text, and the documentation search escapes quotes in the result links it writes.
---
CHANGELOG.md | 7 +++++++
docs/assets/site.js | 21 ++++++++++++++++-----
2 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 14da29a..a3f754b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,13 @@ and Recore uses semantic versioning.
## [Unreleased]
+### Fixed
+
+- The website's policy picker builds its sentence from text nodes instead of
+ markup, so a policy name read from the page is always shown as text and can
+ never run as HTML (CodeQL `js/xss-through-dom`). The documentation search
+ also escapes quotes in the result links it writes.
+
### Added
- Recore is archived on Zenodo. The README carries the DOI badge and both DOIs
diff --git a/docs/assets/site.js b/docs/assets/site.js
index 092374d..fb3dedd 100644
--- a/docs/assets/site.js
+++ b/docs/assets/site.js
@@ -553,9 +553,20 @@
b.setAttribute("aria-pressed", b.getAttribute("data-policy") === policy ? "true" : "false");
});
if (summary) {
- summary.innerHTML =
- "With " + policy + ", " + putBack + " of " + total + " go into the corrected matrix. " +
- "The other " + (total - putBack) + " stay in the states file and orthology_evidence.tsv, with the reason.";
+ // Built from nodes, not markup: the policy name is read from the
+ // page, and it goes in as text.
+ var code = function (text) {
+ var el = document.createElement("code");
+ el.textContent = text;
+ return el;
+ };
+ var count = document.createElement("b");
+ count.textContent = putBack + " of " + total;
+ summary.textContent = "";
+ summary.append(
+ "With ", code(policy), ", ", count, " go into the corrected matrix. The other " + (total - putBack) +
+ " stay in the states file and ", code("orthology_evidence.tsv"), ", with the reason."
+ );
}
}
buttons.forEach(function (b) {
@@ -599,7 +610,7 @@
var active = -1;
function escapeHtml(text) {
- return text.replace(/&/g, "&").replace(//g, ">");
+ return text.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
}
// Words match where a word starts, so "min" finds --min-prevalence and
@@ -669,7 +680,7 @@
var e = hit.entry;
var title = e.section ? e.page + " \u203a " + e.section : e.page;
return (
- '' + highlight(title, words) + "" +
+ '' + highlight(title, words) + "" +
highlight(snippet(e.text, words[0]), words) + ""
);
})