Security review: CVE scan (incl. eMudhra CA compromise) and hardening #1

Closed
opened 2026-10-30 17:43:22 -07:00 by joelbrock · 0 comments
Owner

Results of a security code review and CVE scan run on 2026-10-30.

Findings

eMudhra intermediate CA key compromise (CVE-2026-111943, -113470, -91403, -114820, -115557)

  • The game is not affected. End users' browsers already block the compromised intermediates, and the static site makes no outbound TLS calls.
  • No project endpoint chains to eMudhra. Gitea uses Let's Encrypt, GitHub uses Sectigo, and Google Fonts and the npm registry use Google Trust Services.
  • The Cloudflare Pages build image's default Node 22.23.4 includes the fix.
  • Dev machine: Node 26.13.0, Homebrew OpenJDK 27.0.1 and Python (Homebrew ca-certificates 2026-10-20 / certifi 2026.10.23) are all clean. The macOS /etc/ssl/cert.pem bundle still lists the emSign G1, ECC G3, C1 and C3 roots, and it is used by Apple's CLI curl/git/python3. Workaround: export SSL_CERT_FILE=/opt/homebrew/etc/openssl@4/cert.pem. (Local action, not a repo change.)

npm dependencies: 49 vulnerabilities (2 critical, 28 high, 19 moderate)

All of them come from the single dependency, claude-flow@3.7.0-alpha.72. The game never loads it. Notable ones: protobufjs RCE (GHSA-xq3m-2v4x-88gg), agentic-flow MCP command injection (GHSA-vcv2-r9jh-99m5), adm-zip arbitrary file overwrite, and undici TLS validation bypass. Cloudflare Pages can auto-install dependencies from the lockfile.

Application code: no vulnerabilities found

  • Save data from localStorage is size-capped, schema-checked and clamped (loadProgress()), and the turtle name is sanitized.
  • All user/save-derived text is rendered via textContent. innerHTML is only used with static templates.
  • There's no eval / new Function / postMessage, and the service worker is same-origin GET only.
  • _headers has a strong CSP and full security-header set.
  • No secrets anywhere in git history.

Low-severity hardening

  • Google Fonts was the only third-party origin: it leaked visitor IPs, had no integrity check, and wasn't available offline.
  • style-src 'unsafe-inline' remains (low risk, since there's no HTML injection sink).
  • interest-cohort=() in Permissions-Policy is obsolete and harmless.

Tasks

  • Remove package.json / package-lock.json (clears all 49 audit findings; Pages has nothing to install)
  • Self-host the Outfit font, drop the Google origins from the CSP, precache the font in the SW, bump CACHE_NAME to v18
  • Pin the local .mcp.json ruflo@latest to ruflo@3.65.1 (local, untracked)
  • Update CLAUDE.md with the Gitea → GitHub mirror → Pages deploy flow (local, untracked)
  • Make Gitea the origin remote locally
  • Set SSL_CERT_FILE on the dev Mac (eMudhra roots in the macOS CLI bundle)
  • Optional: move inline style= attributes into CSS and drop 'unsafe-inline'
  • Optional: remove interest-cohort=() from Permissions-Policy
Results of a security code review and CVE scan run on 2026-10-30. ## Findings ### eMudhra intermediate CA key compromise (CVE-2026-111943, -113470, -91403, -114820, -115557) - **The game is not affected.** End users' browsers already block the compromised intermediates, and the static site makes no outbound TLS calls. - No project endpoint chains to eMudhra. Gitea uses Let's Encrypt, GitHub uses Sectigo, and Google Fonts and the npm registry use Google Trust Services. - The Cloudflare Pages build image's default Node 22.23.4 includes the fix. - Dev machine: Node 26.13.0, Homebrew OpenJDK 27.0.1 and Python (Homebrew `ca-certificates` 2026-10-20 / certifi 2026.10.23) are all clean. The macOS `/etc/ssl/cert.pem` bundle still lists the emSign G1, ECC G3, C1 and C3 roots, and it is used by Apple's CLI `curl`/`git`/`python3`. Workaround: `export SSL_CERT_FILE=/opt/homebrew/etc/openssl@4/cert.pem`. *(Local action, not a repo change.)* ### npm dependencies: 49 vulnerabilities (2 critical, 28 high, 19 moderate) All of them come from the single dependency, `claude-flow@3.7.0-alpha.72`. The game never loads it. Notable ones: protobufjs RCE (GHSA-xq3m-2v4x-88gg), agentic-flow MCP command injection (GHSA-vcv2-r9jh-99m5), adm-zip arbitrary file overwrite, and undici TLS validation bypass. Cloudflare Pages can auto-install dependencies from the lockfile. ### Application code: no vulnerabilities found - Save data from `localStorage` is size-capped, schema-checked and clamped (`loadProgress()`), and the turtle name is sanitized. - All user/save-derived text is rendered via `textContent`. `innerHTML` is only used with static templates. - There's no `eval` / `new Function` / `postMessage`, and the service worker is same-origin GET only. - `_headers` has a strong CSP and full security-header set. - No secrets anywhere in git history. ### Low-severity hardening - Google Fonts was the only third-party origin: it leaked visitor IPs, had no integrity check, and wasn't available offline. - `style-src 'unsafe-inline'` remains (low risk, since there's no HTML injection sink). - `interest-cohort=()` in `Permissions-Policy` is obsolete and harmless. ## Tasks - [x] Remove `package.json` / `package-lock.json` (clears all 49 audit findings; Pages has nothing to install) - [x] Self-host the Outfit font, drop the Google origins from the CSP, precache the font in the SW, bump `CACHE_NAME` to v18 - [x] Pin the local `.mcp.json` `ruflo@latest` to `ruflo@3.65.1` *(local, untracked)* - [x] Update `CLAUDE.md` with the Gitea → GitHub mirror → Pages deploy flow *(local, untracked)* - [x] Make Gitea the `origin` remote locally - [ ] Set `SSL_CERT_FILE` on the dev Mac (eMudhra roots in the macOS CLI bundle) - [ ] Optional: move inline `style=` attributes into CSS and drop `'unsafe-inline'` - [ ] Optional: remove `interest-cohort=()` from `Permissions-Policy`
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: designslife/tortugotchi#1