From 2b087f7dc1c10b85ff14a645086e47bbdd4c27cb Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 21 Jun 2026 14:26:08 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM]=20?= =?UTF-8?q?Fix=20SecurityError=20crash=20from=20strict=20privacy=20modes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .jules/sentinel.md | 4 ++++ i18n.js | 14 +++++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 535867d..499037d 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -6,3 +6,7 @@ **Vulnerability:** Unvalidated user input from `location.search` was used directly as an object key (`messages[query]`). This allowed an attacker to supply `?lang=__proto__` or `?lang=valueOf`, resulting in `messages[query]` returning built-in objects or functions rather than the intended language strings. **Learning:** Checking for truthiness like `messages[query] ? query : ...` fails securely when dealing with inherited Object properties. Without a whitelist, user input accessing un-prototyped object keys is dangerous. **Prevention:** Always validate external input against a strict whitelist (e.g. `['ko', 'en'].includes(query)`) before using it in application logic, or ensure dictionaries are created without prototypes (`Object.create(null)`). +## 2024-06-21 - Fix SecurityError crash from strict privacy modes +**Vulnerability:** Unhandled exceptions when accessing `localStorage` in strict browser privacy modes (e.g., when cookies are blocked). +**Learning:** Browsers throw a `SecurityError` when `localStorage` is accessed and the user has blocked third-party cookies or is in a strict privacy mode. If unhandled, this crashes the executing script, leading to a degraded user experience (DoS-like behavior for privacy-conscious users). +**Prevention:** Always wrap `localStorage.getItem` and `localStorage.setItem` in `try-catch` blocks to fail securely and fall back to sensible defaults. diff --git a/i18n.js b/i18n.js index e9707b5..327cb7e 100644 --- a/i18n.js +++ b/i18n.js @@ -290,8 +290,12 @@ function preferredLanguage() { const query = new URLSearchParams(window.location.search).get("lang"); if (allowed.includes(query)) return query; - const saved = localStorage.getItem("cwl-language"); - if (allowed.includes(saved)) return saved; + try { + const saved = localStorage.getItem("cwl-language"); + if (allowed.includes(saved)) return saved; + } catch (error) { + // Fail securely: ignore localStorage errors in strict privacy modes + } return navigator.language?.toLowerCase().startsWith("ko") ? "ko" : "en"; } @@ -355,7 +359,11 @@ function setLanguage(lang) { } }); - localStorage.setItem("cwl-language", lang); + try { + localStorage.setItem("cwl-language", lang); + } catch (error) { + // Fail securely: ignore localStorage errors + } currentLang = lang; }