diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b68c181..ca1ff34 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "OpenTaxMap", - "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04@sha256:d94c97dd9cacf183d0a6fd12a8e87b526e9e928307674ae9c94139139c0c6eae", "features": { "ghcr.io/devcontainers/features/node:1": { "version": "22" }, diff --git a/api/version.mjs b/api/version.mjs index 326b1af..f85dc89 100644 --- a/api/version.mjs +++ b/api/version.mjs @@ -15,6 +15,7 @@ export default { try { const gh = await fetch(RELEASES_API, { headers: { 'user-agent': 'opentaxmap', accept: 'application/vnd.github+json' }, + signal: AbortSignal.timeout(5000), }) if (gh.ok) { const data = await gh.json() diff --git a/scripts/prerender.mjs b/scripts/prerender.mjs index 1c6c395..9f5bb2a 100644 --- a/scripts/prerender.mjs +++ b/scripts/prerender.mjs @@ -48,6 +48,12 @@ const latestYear = String(Math.max(...data.years)) let count = 0 for (const loc of data.localities) { + // Safe today only because build_data.py collapses slugs to [a-z0-9-]; make + // that guarantee local so a future data-pipeline change can't turn + // loc.slug into a path-traversal segment for the join() below. + if (!/^[a-z0-9][a-z0-9-]*$/.test(loc.slug)) { + throw new Error(`unsafe locality slug: ${JSON.stringify(loc.slug)}`) + } const b = loc.benefits[latestYear] const years = Object.keys(loc.benefits).sort() const rateText = b diff --git a/src/main.js b/src/main.js index 57a9f39..b8ff880 100644 --- a/src/main.js +++ b/src/main.js @@ -32,7 +32,10 @@ const state = { changes: params.get('changes') === '1', selected: null, } -if (!STRINGS[state.lang]) state.lang = 'he' +// Strict allowlist, not a STRINGS[key] lookup: a ?lang=__proto__ (or any +// other Object.prototype key) would otherwise pass this guard and later +// blow up at STRINGS[state.lang].aboutDataItems, reflected client-side DoS. +if (state.lang !== 'he' && state.lang !== 'en') state.lang = 'he' let t = makeT(state.lang) let data = null