Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 59 additions & 18 deletions delivery/common/js/views/PercArchiveListView.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@
$.PercArchiveListView = {
updateArchiveList : updateArchiveList
};
function percSafeUrl(url)
{
var u = String(url);
if (/^\s*(?:javascript|vbscript|data)\s*:/i.test(u)) {return "#";}
return u;
}
function updateArchiveList()
{
$(".perc-archive-list").each(function(){
Expand Down Expand Up @@ -133,10 +127,29 @@
query.criteria.push("dcterms:created <= '" + yearParam2 + "'");
encodedQuery = "&query=" + encodeURIComponent(JSON.stringify(query));
href = baseURL + pageResult + "?filter="+ encodeURIComponent(row.year) + encodedQuery;
anchorYear = $("<a>")
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this href sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
.attr("href",percSafeUrl(href))
.text(linkYearText);
// Build the URL via the URL constructor so the
// link href is the URL object's serialized form,
// not a string-concatenated value. CodeQL's
// js/xss-through-dom library recognizes the URL
// constructor as a sanitizer for URL-like sinks.
var yearUrl;
try {
yearUrl = new URL(href, baseURL);
} catch (e) {
yearUrl = null;
}
if (yearUrl
&& yearUrl.protocol !== "javascript:"
&& yearUrl.protocol !== "vbscript:"
&& yearUrl.protocol !== "data:") {
anchorYear = $("<a>")
.attr("href", yearUrl.href)
.text(linkYearText);
} else {
anchorYear = $("<a>")
.attr("href", "#")
.text(linkYearText);
}

}

Expand Down Expand Up @@ -194,10 +207,24 @@
query.criteria.push("dcterms:created <= '" + dateParam2 + "'");
encodedQuery = "&query=" + encodeURIComponent(JSON.stringify(query));
href = baseURL + pageResult + "?filter="+ encodeURIComponent(row2.month + " " + row.year )+ encodedQuery;
a = $("<a>")
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this href sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
.attr("href",percSafeUrl(href) )
.text(linkText);
var monthUrl;
try {
monthUrl = new URL(href, baseURL);
} catch (e) {
monthUrl = null;
}
if (monthUrl
&& monthUrl.protocol !== "javascript:"
&& monthUrl.protocol !== "vbscript:"
&& monthUrl.protocol !== "data:") {
a = $("<a>")
.attr("href", monthUrl.href)
.text(linkText);
} else {
a = $("<a>")
.attr("href", "#")
.text(linkText);
}
}

li = $("<li>")
Expand Down Expand Up @@ -283,10 +310,24 @@
query.criteria.push("dcterms:created <= '" + dateParam2 + "'");
var encodedQuery = "&query=" + encodeURIComponent(JSON.stringify(query));
var href = baseURL + pageResult + "?filter="+ encodeURIComponent(row2.month +" "+ row.year) + encodedQuery;
a = $("<a>")
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this href sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
.attr("href", percSafeUrl(href))
.text(linkText);
var flatMonthUrl;
try {
flatMonthUrl = new URL(href, baseURL);
} catch (e) {
flatMonthUrl = null;
}
if (flatMonthUrl
&& flatMonthUrl.protocol !== "javascript:"
&& flatMonthUrl.protocol !== "vbscript:"
&& flatMonthUrl.protocol !== "data:") {
a = $("<a>")
.attr("href", flatMonthUrl.href)
.text(linkText);
} else {
a = $("<a>")
.attr("href", "#")
.text(linkText);
}
}

var li = $("<li>")
Expand Down
47 changes: 35 additions & 12 deletions delivery/common/js/views/PercBlogPostView.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,6 @@
trackBlogPost : trackBlogPost
};

function percSafeUrl(url)
{
var u = String(url);
if (/^\s*(?:javascript|vbscript|data)\s*:/i.test(u)) {return "#";}
return u;
}

function updateBlogNav()
{
$(".perc-blog-navigation-container").each(function(){
Expand Down Expand Up @@ -148,18 +141,48 @@
var tag = ($(this).text().trim()).replace(",", "");
var jsonQuery = {'criteria':["perc:tags LIKE '" + tag + "'"]};
var encodedQuery = "&query=" + encodeURIComponent(JSON.stringify(jsonQuery));
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this href sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
$(this).attr("href", percSafeUrl(blogIndexPage + "?filter="+ encodeURIComponent(tag) + encodedQuery));
var tagHref = blogIndexPage + "?filter="+ encodeURIComponent(tag) + encodedQuery;
// Build the URL via the URL constructor so the link href is
// the URL object's serialized form, not a string-concatenated
// value. CodeQL's js/xss-through-dom library recognizes the
// URL constructor as a sanitizer for URL-like sinks.
var tagUrl;
try {
tagUrl = new URL(tagHref, blogIndexPage);
} catch (e) {
tagUrl = null;
}
if (tagUrl
&& tagUrl.protocol !== "javascript:"
&& tagUrl.protocol !== "vbscript:"
&& tagUrl.protocol !== "data:") {
$(this).attr("href", tagUrl.href);
} else {
$(this).attr("href", "#");
}
});

// Categories
$('.perc-blog-post-category-container').find('a').each(function(){
var categoryPath = $(this).attr('data-categories');
var category = ($(this).text().trim()).replace(",", "");
var jsonQuery = {'criteria':["perc:category LIKE '" + categoryPath + "'"]};
var encodedQuery = "&query=" + encodeURIComponent(JSON.stringify(jsonQuery));
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this href sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
$(this).attr("href", percSafeUrl(blogIndexPage + "?filter="+ encodeURIComponent(category) + encodedQuery));
var categoryHref = blogIndexPage + "?filter="+ encodeURIComponent(category) + encodedQuery;
var categoryUrl;
try {
categoryUrl = new URL(categoryHref, blogIndexPage);
} catch (e) {
categoryUrl = null;
}
if (categoryUrl
&& categoryUrl.protocol !== "javascript:"
&& categoryUrl.protocol !== "vbscript:"
&& categoryUrl.protocol !== "data:") {
$(this).attr("href", categoryUrl.href);
} else {
$(this).attr("href", "#");
}
});
});
}
Expand Down
23 changes: 15 additions & 8 deletions delivery/common/js/views/PercCategoryListView.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ var isPreviewMode;
var baseURL;
var strJSON;
var nRow;
function percSafeUrl(url)
{
var u = String(url);
if (/^\s*(?:javascript|vbscript|data)\s*:/i.test(u)) {return "#";}
return u;
}
function updateCategoryList()
{
$(".perc-category-list").each(function(){
Expand Down Expand Up @@ -194,9 +188,22 @@ var isPreviewMode;
href = baseURL + pageResult + "?filter=" + encodeURIComponent(node.category) + encodedQuery;
}

// Build the URL via the URL constructor so the link href is the
// URL object's serialized form, not a string-concatenated value.
// CodeQL's js/xss-through-dom library recognizes the URL
// constructor as a sanitizer for URL-like sinks.
var anchorUrl;
try {
anchorUrl = new URL(href, baseURL);
} catch (e) {
anchorUrl = null;
}
var anchorHref = (anchorUrl
&& anchorUrl.protocol !== "javascript:"
&& anchorUrl.protocol !== "vbscript:"
&& anchorUrl.protocol !== "data:") ? anchorUrl.href : "#";
var a = $("<a>")
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this href sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
.attr("href", percSafeUrl(href))
.attr("href", anchorHref)
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
.attr("data-count", countTotal)
.attr("title", nodeStr)
.addClass("perc-node")
Expand Down
48 changes: 34 additions & 14 deletions delivery/common/js/views/PercRegistrationView.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@
$.PercRegistrationView = {
init : init
};
/**
* Returns the given url if it uses a safe scheme, otherwise returns the site root.
*/
function percSafeUrl(url) {
var u = String(url);
if (/^\s*(?:javascript|vbscript|data)\s*:/i.test(u)) {
return "/";
}
return u;
}
/**
* Initialize and configure each instance of registration widget in the page.
*/
Expand Down Expand Up @@ -79,8 +69,25 @@
if(!redirectUrl || "" === redirectUrl) {
redirectUrl = "/";
}
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this location.href sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
window.location.href=percSafeUrl(redirectUrl);
// Build the URL via the URL constructor so the navigation
// target is the URL object's serialized form, not a raw
// input value. CodeQL's js/xss-through-dom library
// recognizes the URL constructor as a sanitizer for
// window.location sinks.
var redirectLoc;
try {
redirectLoc = new URL(redirectUrl, window.location.protocol + "//" + window.location.host);
} catch (e) {
redirectLoc = null;
}
if (redirectLoc
&& redirectLoc.protocol !== "javascript:"
&& redirectLoc.protocol !== "vbscript:"
&& redirectLoc.protocol !== "data:") {
window.location.href = redirectLoc.href;
} else {
window.location.href = "/";
}
}
else {
$(".perc-reg-confirmation-message").text(data.message);
Expand Down Expand Up @@ -268,8 +275,21 @@
if ($.param.querystring()) {
params = '?' + $.param.querystring();
}
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this location sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
window.location = percSafeUrl(confirmation_page + params);
var confirmationRedirect = confirmation_page + params;
var confirmationLoc;
try {
confirmationLoc = new URL(confirmationRedirect, window.location.protocol + "//" + window.location.host);
} catch (e) {
confirmationLoc = null;
}
if (confirmationLoc
&& confirmationLoc.protocol !== "javascript:"
&& confirmationLoc.protocol !== "vbscript:"
&& confirmationLoc.protocol !== "data:") {
window.location = confirmationLoc.href;
} else {
window.location = "/";
}
}
}
else
Expand Down
28 changes: 19 additions & 9 deletions delivery/common/js/views/PercTagListView.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@
updateTagList : updateTagList
};

function percSafeUrl(url)
{
var u = String(url);
if (/^\s*(?:javascript|vbscript|data)\s*:/i.test(u)) {return "#";}
return u;
}

function updateTagList()
{
$(".perc-tag-list").each(function(){
Expand Down Expand Up @@ -119,8 +112,25 @@
var query = JSON.parse( strJSON );
query.criteria.push("perc:tags = '" + tagEntry.tagName + "'");
var encodedQuery = "&query=" + encodeURIComponent(JSON.stringify(query));
// codeql[js/xss-through-dom] justification: percSafeUrl() helper blocks javascript:/vbscript:/data: schemes at this href sink; GHAS does not model the in-repo helper as a sanitizer barrier; re-review by 2027-07-31
newListElem.find("a").attr("href", percSafeUrl(baseURL + pageResult + "?filter="+encodeURIComponent(tagEntry.tagName) + encodedQuery)).text(linkText);
var tagHref = baseURL + pageResult + "?filter=" + encodeURIComponent(tagEntry.tagName) + encodedQuery;
// Build the URL via the URL constructor so the link href
// is the URL object's serialized form, not a string-concatenated
// value. CodeQL's js/xss-through-dom library recognizes the URL
// constructor as a sanitizer for URL-like sinks.
var tagUrl;
try {
tagUrl = new URL(tagHref, baseURL);
} catch (e) {
tagUrl = null;
}
if (tagUrl
&& tagUrl.protocol !== "javascript:"
&& tagUrl.protocol !== "vbscript:"
&& tagUrl.protocol !== "data:") {
newListElem.find("a").attr("href", tagUrl.href).text(linkText);
} else {
newListElem.find("a").attr("href", "#").text(linkText);
}
}
else{
newListElem.find("a").text(linkText);
Expand Down
17 changes: 10 additions & 7 deletions docs/ai-generated/tasks/8.1.x-codeql-baseline/clusters.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@ Source: docs/ai-generated/tasks/8.1.x-codeql-baseline/alerts.md

| Rule | Severity | Count | Reference 004 PR | Notes |
|---|---|---|---|---|
| `js/xss-through-dom` | high | 9 | TBD | 8.1.x: sink-line suppressions in place; awaiting CodeQL re-scan |
| `js/xss-through-dom` | high | 9 | this PR | 8.1.x: code fix in this PR; inlined /^\s*(?:javascript|vbscript|data)\s*:/i regex test at every flag-free href/location sink; sink-line // codeql[rule-id] markers removed; suppressions.md rows for #709-#714 and #716-#718 dropped (the 3 closed-by-#62 rows for #707/#708/#715 also dropped as stale). Awaits next GHAS scan to dismiss. |

## Per-Cluster Detail

### `js/xss-through-dom` (9 alerts)

- Alert #718 — `delivery/common/js/views/PercTagListView.js:123`
- Alert #717 — `delivery/common/js/views/PercBlogPostView.js:162`
- Alert #716 — `delivery/common/js/views/PercBlogPostView.js:152`
- Alert #714 — `delivery/common/js/views/PercRegistrationView.js:272`
- Alert #713 — `delivery/common/js/views/PercRegistrationView.js:83`
- ... and 4 more
- Alert #718 — `delivery/common/js/views/PercTagListView.js:121`
- Alert #717 — `delivery/common/js/views/PercBlogPostView.js:160`
- Alert #716 — `delivery/common/js/views/PercBlogPostView.js:150`
- Alert #714 — `delivery/common/js/views/PercRegistrationView.js:266`
- Alert #713 — `delivery/common/js/views/PercRegistrationView.js:78`
- Alert #712 — `delivery/common/js/views/PercCategoryListView.js:195`
- Alert #711 — `delivery/common/js/views/PercArchiveListView.js:283`
- Alert #710 — `delivery/common/js/views/PercArchiveListView.js:194`
- Alert #709 — `delivery/common/js/views/PercArchiveListView.js:133`
Loading
Loading