From cbbecc27c61a37374848e539539228a474724dbf Mon Sep 17 00:00:00 2001 From: Richard Nixon Date: Sun, 17 May 2026 16:08:45 +0100 Subject: [PATCH] fix(memorial): sanitize remaining XSS-prone render paths The references fix in #331 covered only one of the render paths. Apply the same DOM-construction pattern to personal info, obituary, social media, contributions, gallery and the help-link fallbacks, plus the people grid in index.html. maintext is still rendered as HTML to preserve existing formatted bios; flagged for a DOMPurify follow-up. --- index.html | 29 ++++++------- memorial.html | 113 ++++++++++++++++++++++++++++---------------------- 2 files changed, 75 insertions(+), 67 deletions(-) diff --git a/index.html b/index.html index c21d3e4..d13e714 100644 --- a/index.html +++ b/index.html @@ -40,28 +40,23 @@ }); for (var p = 0; p < peoplelist.length; p++) { - var displayname = peoplelist[p]["displayname"]; + var displayname = String(peoplelist[p]["displayname"] || ""); var file = peoplelist[p]["filename"]; - var card; + var $card; if (file == "") { - card = - '"; + $card = $("
") + .addClass("person-card no-link") + .attr("data-name", displayname.toLowerCase()) + .text(displayname); } else { - card = - '' + - displayname + - ""; + $card = $("") + .attr("href", "memorial.html?name=" + encodeURIComponent(file)) + .addClass("person-card") + .attr("data-name", displayname.toLowerCase()) + .text(displayname); } - $("#people-grid").append(card); + $("#people-grid").append($card); } $(".loading-message").remove(); diff --git a/memorial.html b/memorial.html index 7d0a012..26849a8 100644 --- a/memorial.html +++ b/memorial.html @@ -29,7 +29,7 @@ var params = new URLSearchParams(window.location.search); if (params.get("name") != null) { var name = params.get("name"); - person = "/people/" + name + ".json"; + person = "/people/" + encodeURIComponent(name) + ".json"; } else { person = "/people/person.json"; } @@ -45,37 +45,47 @@ } } + function txt(value) { + return document.createTextNode(value == null ? "" : String(value)); + } + $.getJSON(person, function (data) { var fullname = data.firstname + " " + data.lastname; if (data.handle != "") { fullname += " (" + data.handle + ")"; } - $("title").append(fullname); - $("#subtitle").append(fullname); - $("#memorial-name").append(fullname); - $(".birth").append(data.birth); - $(".death").append(data.death); - $(".issue").append(data.issue); + document.title = document.title + fullname; + $("#subtitle").append(txt(fullname)); + $("#memorial-name").text(fullname); + $(".birth").append(txt(data.birth)); + $(".death").append(txt(data.death)); if (data.affiliations == null || data.affiliations == "") { - $(".affiliations").append("None"); + $(".affiliations").append(txt("None")); } else { - $(".affiliations").append(data.affiliations); + $(".affiliations").append(txt(data.affiliations)); } if (data.obituary != null && data.obituary != "") { $(".obituary").append( - 'Obituary', + $("").attr("href", safeUrl(data.obituary)).text("Obituary"), ); } + var issueUrl; if (data.issue == null || data.issue == "") { - data.issue = + issueUrl = "https://github.com/restincode/restincode/blob/master/CONTRIBUTING.md"; } else { - data.issue = - "https://github.com/restincode/restincode/issues/" + data.issue; + issueUrl = + "https://github.com/restincode/restincode/issues/" + + encodeURIComponent(data.issue); + } + var safeIssueUrl = safeUrl(issueUrl); + + function helpLink() { + return $("").attr("href", safeIssueUrl).text("here."); } if (data.mainimage == "") { @@ -84,17 +94,21 @@ .attr("alt", "placeholder photo"); } else { $(".memorial-main-image") - .attr("src", data.mainimage) + .attr("src", safeUrl(data.mainimage)) .attr("alt", "Main photo of " + fullname); } if (data.maintext == "") { $("#memorial-text").append( - "

No information has been submitted for this person. Help us by submitting here.

", + $("

").append( + "No information has been submitted for this person. Help us by submitting ", + helpLink(), + ), ); } else { + // maintext is intentionally rendered as HTML for formatted bios. + // Residual XSS risk is mitigated by PR review; track follow-up + // to integrate DOMPurify for defense-in-depth. $("#memorial-text").append(data.maintext); } @@ -103,17 +117,18 @@ !data.socialmedialinks.length ) { $("#social-media").append( - "

No social media links have been submitted for this person. Help us by submitting here.

", + $("

").append( + "No social media links have been submitted for this person. Help us by submitting ", + helpLink(), + ), ); } else { for (var s = 0; s < data.socialmedialinks.length; s++) { var sitename = data.socialmedialinks[s]["sitename"]; var siteurl = data.socialmedialinks[s]["siteurl"]; - var social = - '' + sitename + ""; - $("#social-media").append(social); + $("#social-media").append( + $("").attr("href", safeUrl(siteurl)).text(sitename), + ); } } @@ -121,7 +136,7 @@ $("#references").append( $("

").append( "No references have been submitted for this person. Help us by submitting ", - $("").attr("href", safeUrl(data.issue)).text("here."), + helpLink(), ), ); } else { @@ -139,52 +154,50 @@ !data.contributions.length ) { $("#contributions-list").append( - "

  • No contributions have been submitted for this person. Help us by submitting here.
  • ", + $("
  • ").append( + "No contributions have been submitted for this person. Help us by submitting ", + helpLink(), + ), ); } else { for (var x = 0; x < data.contributions.length; x++) { var title = data.contributions[x]["title"]; var url = data.contributions[x]["url"]; var text = data.contributions[x]["description"]; - var cont; + var $li = $("
  • "); if (url == "") { - cont = "
  • " + title + " - " + text + "
  • "; + $li.append($("").text(title)); } else { - cont = - "
  • " + - title + - " - " + - text + - "
  • "; + $li.append($("").attr("href", safeUrl(url)).text(title)); } - $("#contributions-list").append(cont); + $li.append(txt(" - " + text)); + $("#contributions-list").append($li); } } if (!Array.isArray(data.gallery) || !data.gallery.length) { $("#nogallery").append( - "

    No images have been submitted for this person yet. Help us by submitting here.

    ", + $("

    ").append( + "No images have been submitted for this person yet. Help us by submitting ", + helpLink(), + ), ); } else { for (var i = 0; i < data.gallery.length; i++) { var imgurl = safeUrl(data.gallery[i]["url"]); var imgtitle = data.gallery[i]["title"]; var caption = data.gallery[i]["caption"]; - var image = - "

    "; - $("#gallery").append(image); + $("#gallery").append( + $("
    ") + .addClass("memorial-gallery") + .append( + $("") + .attr("src", imgurl) + .attr("alt", imgtitle) + .attr("loading", "lazy"), + $("
    ").text(caption), + ), + ); } }