From 4a12b009aa96ebfbf1b037bb5747c20cbe6e04cb Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Sat, 26 Sep 2026 05:49:18 +0000 Subject: [PATCH] Every runtime CDN script and stylesheet is an exact version with an integrity hash maplibre-gl@5 and maplibre-gl-geocoder@1 were floating ranges, and no runtime loader set `integrity`, so a CDN could serve any bytes to every partner's visitors unnoticed (CRITIC-5). - library/constants/cdn.js is the one registry: mapbox-gl 3.24.0, maplibre-gl 5.24.0 (the release the @5 range already resolved to), both geocoders (1.9.4 / 5.0.0) and d3 7.9.0, each with its sha384. Every host answers Access-Control-Allow-Origin: *, so integrity + crossorigin work cross-origin. - ensureEngineScript / ensureEngineCSS, the geocoder loaders (library and PPLR) and the generator's static MapLibre tags set integrity + crossorigin from it; the embed snippet's engine preload matches. - check:cdn-pins (gates:post): no floating CDN url in shipped code, and every one is in the registry; --online re-fetches each and compares the hash (all 9 match today). MapLibre stays on 5.x knowingly. GHSA-jrc7-96c5-q579 (DOM.sanitize, reached through a source's attribution string) affects <= 6.4.0, and 6.x is ESM-only (no UMD global), so the upgrade is a loader migration of its own. The attribution strings rendered today come from our configured basemap styles and our own sources; the note in cdn.js says who is exposed until then. --- internal/check-cdn-pins.mjs | 57 +++++++++++++++++++ internal/generate-tree.mjs | 22 +++---- .../map-controls/GeocoderComponent.vue | 11 ++-- library/composables/useMapInstance.js | 17 +++--- library/constants/cdn.js | 44 ++++++++++++++ .../pplr-data-maps/src/utils/pplrData.js | 11 ++-- 6 files changed, 127 insertions(+), 35 deletions(-) create mode 100644 internal/check-cdn-pins.mjs create mode 100644 library/constants/cdn.js diff --git a/internal/check-cdn-pins.mjs b/internal/check-cdn-pins.mjs new file mode 100644 index 000000000..20ff43da6 --- /dev/null +++ b/internal/check-cdn-pins.mjs @@ -0,0 +1,57 @@ +#!/usr/bin/env node +/** + * check-cdn-pins — every runtime third-party script/stylesheet is an EXACT version with an integrity hash. + * + * CRITIC-5 (2026-09-26): maplibre-gl@5 and maplibre-gl-geocoder@1 were floating ranges, and no runtime + * loader set `integrity`, so a CDN could serve any bytes to every partner's visitors unnoticed. + * library/constants/cdn.js is now the one registry; loaders set integrity + crossorigin from it. + * + * OFFLINE (default, in gates:post): in shipped code (library/, plugin-designs/ except scripts/, + * internal/generate-tree.mjs) no jsDelivr/unpkg/esm.sh/api.mapbox.com JS or CSS URL is a floating + * range (@7, @1.2, latest), and every such URL is either in the registry or on the reviewed list below. + * --online: also re-fetches every registry URL and requires its sha384 to equal the pinned hash. + * EXIT 0 pass · 1 fail · 75 (online) network unavailable + */ +import { execFileSync } from 'node:child_process' +import { createHash } from 'node:crypto' +import { resolve, dirname } from 'node:path' +import { fileURLToPath } from 'node:url' +import { CDN } from '../library/constants/cdn.js' + +const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..') +const ONLINE = process.argv.includes('--online') +// Loaded through something other than a ` + + ` : `\n\n` + scriptEmbed + ? `\n\n` + scriptEmbed : scriptEmbed, }, ...(instances.length ? { instances } : {}), diff --git a/library/components/map-controls/GeocoderComponent.vue b/library/components/map-controls/GeocoderComponent.vue index 08388ff66..0df933cc5 100644 --- a/library/components/map-controls/GeocoderComponent.vue +++ b/library/components/map-controls/GeocoderComponent.vue @@ -62,6 +62,7 @@ geocoder — the raw MapboxGeocoder instance (for advanced usage) -->