From 30890c32618ed2041db078ea7cc4f83cc0c03552 Mon Sep 17 00:00:00 2001 From: Yusef Habib Fernandez Date: Fri, 4 Sep 2026 18:13:20 +0200 Subject: [PATCH 1/2] fix(aggregator): pin home page Prism assets with Subresource Integrity The home page loaded prism.min.js and its theme from the Juno CDN over the .raw.icp0.io gateway. A raw response is a single-replica query response with no certification, and the tags carried no integrity attribute. Nothing verified the bytes, so a substituted script could control the whole page. Both tags now use the certified .icp0.io gateway and carry an SHA-384 integrity hash plus crossorigin="anonymous". The CDN sends Access-Control-Allow-Origin: *, so the CORS fetch succeeds. A new unit test asserts that every external script and stylesheet on the home page has an integrity hash, has crossorigin="anonymous", and does not use a raw gateway host. --- CHANGELOG-Sns_Aggregator.md | 2 + rs/sns_aggregator/src/assets.rs | 3 ++ rs/sns_aggregator/src/assets/tests.rs | 58 +++++++++++++++++++++++++++ rs/sns_aggregator/src/index.html | 20 +++++++-- 4 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 rs/sns_aggregator/src/assets/tests.rs diff --git a/CHANGELOG-Sns_Aggregator.md b/CHANGELOG-Sns_Aggregator.md index 99ba4965904..04798ed351f 100644 --- a/CHANGELOG-Sns_Aggregator.md +++ b/CHANGELOG-Sns_Aggregator.md @@ -15,6 +15,8 @@ The SNS Aggregator is released through proposals in the Network Nervous System. ### Fixed ### Security +- Pin the home page's Prism script and stylesheet with Subresource Integrity and load them from the certified gateway. + ## [Proposal 137283](https://dashboard.internetcomputer.org/proposal/137283) ### Added - Include SNS Governance metrics. diff --git a/rs/sns_aggregator/src/assets.rs b/rs/sns_aggregator/src/assets.rs index f22ce71103d..07332f48333 100644 --- a/rs/sns_aggregator/src/assets.rs +++ b/rs/sns_aggregator/src/assets.rs @@ -8,6 +8,9 @@ use serde_bytes::ByteBuf; use sha2::{Digest, Sha256}; use std::collections::HashMap; +#[cfg(test)] +mod tests; + /// A standard HTTP header type HeaderField = (String, String); diff --git a/rs/sns_aggregator/src/assets/tests.rs b/rs/sns_aggregator/src/assets/tests.rs new file mode 100644 index 00000000000..d2561d87227 --- /dev/null +++ b/rs/sns_aggregator/src/assets/tests.rs @@ -0,0 +1,58 @@ +//! Tests for the aggregator assets +#![allow(clippy::panic)] +#![allow(clippy::expect_used)] +#![allow(clippy::unwrap_used)] + +/// The home page, exactly as it is compiled into the canister. +const HOME_PAGE: &str = include_str!("../index.html"); + +/// The text of every tag in the given HTML, without the enclosing angle brackets. +/// +/// For example `` yields `link href="x" /`. +fn tag_bodies(html: &str) -> Vec<&str> { + html.split('<') + .skip(1) + .filter_map(|chunk| chunk.split_once('>').map(|(body, _rest)| body)) + .collect() +} + +/// True if the tag body is a tag with the given name, such as `script` or `link`. +fn has_tag_name(tag_body: &str, name: &str) -> bool { + tag_body + .strip_prefix(name) + .is_some_and(|rest| rest.is_empty() || rest.starts_with('/') || rest.starts_with(char::is_whitespace)) +} + +/// Every external ` - + + From 39db1d100173e7b31354b91b5011eb06d4ed2601 Mon Sep 17 00:00:00 2001 From: Yusef Habib Fernandez Date: Fri, 4 Sep 2026 18:26:34 +0200 Subject: [PATCH 2/2] fix(aggregator): add Subresource and stylesheet to the spellcheck dictionary The changelog entry for the Subresource Integrity fix fails the CI spelling job. scripts/spellcheck-changelog rejects both words. --- .config/spellcheck.dic | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.config/spellcheck.dic b/.config/spellcheck.dic index ae45af82cb7..47a03546d79 100644 --- a/.config/spellcheck.dic +++ b/.config/spellcheck.dic @@ -1,4 +1,4 @@ -86 +88 Monterey IC ICP @@ -85,3 +85,5 @@ DoS Ctrl Cmd Banxa +Subresource +stylesheet