Updates the 2026-05-22 audit to reflect the three shipped fixes: - #2 yarn audit CI gate (PR #196) - #3 devDependency vulnerabilities 42 → 0 (PR #196) - #4 style-src 'unsafe-inline' removed from all three CSP layers (PR #197) New score: 72/82 (was 66/82). Sole remaining HIGH: .env keystore password. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1c642f5b37
commit
1b0896f264
1 changed files with 51 additions and 46 deletions
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
Performed by Claude Code (claude-sonnet-4-6) using the `auditing-repo-security` skill.
|
||||
|
||||
> **Status update — 2026-05-23.** Three of eight remediation items shipped: #2 (yarn audit CI gate), #3 (devDependency vulns 42 → 0), and #4 (CSP `style-src 'unsafe-inline'` removed). New score: **72 / 82** (was 66). Sole remaining HIGH: `.env` keystore password in plaintext. See "Remediation Plan" and "Resolved Findings" sections below.
|
||||
|
||||
---
|
||||
|
||||
### Stack Identification
|
||||
|
|
@ -44,26 +46,26 @@ Performed by Claude Code (claude-sonnet-4-6) using the `auditing-repo-security`
|
|||
|
||||
### Executive Summary
|
||||
|
||||
MetaScrub has a genuinely strong privacy and security posture for a client-side-only tool: a strict multi-layer CSP (meta tag + nginx + Cloudflare Pages headers), zero network calls in production, no analytics or telemetry, encrypted-ZIP detection, and ZIP-bomb budgeting. The most concrete finding is a real APK-signing keystore password committed to the local `.env` file in plaintext — while gitignored and not in VCS, it is the private key to the Android release signing trust chain and sits unencrypted on the developer's disk. A second actionable item is 42 devDependency vulnerabilities (2 critical: `minimist` prototype pollution in `madge`), none of which reach the production bundle but which expose CI and local builds. The CSP's `style-src 'unsafe-inline'` and the Capacitor `config.xml` `<access origin="*">` are minor hardening gaps.
|
||||
MetaScrub has a genuinely strong privacy and security posture for a client-side-only tool: a strict multi-layer CSP (meta tag + nginx + Cloudflare Pages headers), zero network calls in production, no analytics or telemetry, encrypted-ZIP detection, and ZIP-bomb budgeting. As of 2026-05-23, the CSP has been tightened to drop `style-src 'unsafe-inline'` (PR #197) and all 42 devDependency vulnerabilities have been resolved with a `yarn audit --level high` CI gate added (PR #196). The most concrete remaining finding is a real APK-signing keystore password held in the local `.env` file in plaintext — while gitignored and not in VCS, it is the private key to the Android release signing trust chain and sits unencrypted on the developer's disk. The Capacitor `config.xml` `<access origin="*">` and a missing HSTS header in the Docker nginx config are minor hardening gaps.
|
||||
|
||||
---
|
||||
|
||||
### Score: 66 / 82
|
||||
### Score: 72 / 82 *(was 66 / 82 at audit time; +6 after 2026-05-23 fixes)*
|
||||
|
||||
*(Domain 1 — AuthN/AuthZ excluded from denominator: local offline tool with no user accounts)*
|
||||
|
||||
| Domain | Max | Score | Key reason |
|
||||
|---|---|---|---|
|
||||
| 1. AuthN/AuthZ | 18 | N/A | No auth surface — local offline tool |
|
||||
| 2. Injection & Input Handling | 16 | 13 | No server-side injection; ZIP-bomb mitigated; `style-src 'unsafe-inline'` |
|
||||
| 3. Secrets & Credential Management | 14 | 10 | Real keystore password in plaintext `.env`; no committed secrets |
|
||||
| 4. Cryptography | 10 | 9 | No custom crypto; APK signing uses v1/v2/v3 correctly |
|
||||
| 5. Data Exposure & Privacy | 10 | 10 | Backup disabled, `lastModified: 0`, eviction on FileEntry removal |
|
||||
| 6. Security Config & Hardening | 10 | 8 | Strong CSP; missing HSTS; `access origin="*"`; `style-src 'unsafe-inline'` |
|
||||
| 7. Dependencies & Supply Chain | 8 | 4 | 2 critical vulns in devDeps; no Dependabot/SCA in CI |
|
||||
| 8. Error Handling & Logging | 6 | 6 | Result<T,E> throughout; no sensitive data in console output |
|
||||
| 9. Code Quality & Hygiene | 5 | 4 | No eval; one unusual Blob dynamic import (not exploitable) |
|
||||
| 10. Infrastructure & Deployment | 3 | 2 | Nginx runs as root; no HSTS; CI uses pinned action versions |
|
||||
| Domain | Max | Score | Δ | Key reason |
|
||||
|---|---|---|---|---|
|
||||
| 1. AuthN/AuthZ | 18 | N/A | — | No auth surface — local offline tool |
|
||||
| 2. Injection & Input Handling | 16 | 14 | +1 | No server-side injection; ZIP-bomb mitigated; ~~`style-src 'unsafe-inline'`~~ ✅ removed |
|
||||
| 3. Secrets & Credential Management | 14 | 10 | — | Real keystore password in plaintext `.env`; no committed secrets |
|
||||
| 4. Cryptography | 10 | 9 | — | No custom crypto; APK signing uses v1/v2/v3 correctly |
|
||||
| 5. Data Exposure & Privacy | 10 | 10 | — | Backup disabled, `lastModified: 0`, eviction on FileEntry removal |
|
||||
| 6. Security Config & Hardening | 10 | 9 | +1 | Strong CSP (~~`style-src 'unsafe-inline'`~~ ✅ removed); missing HSTS; `access origin="*"` |
|
||||
| 7. Dependencies & Supply Chain | 8 | 8 | +4 | ~~2 critical vulns~~ ✅ 0 findings; ~~no Dependabot/SCA in CI~~ ✅ `yarn audit --level high` gate added |
|
||||
| 8. Error Handling & Logging | 6 | 6 | — | Result<T,E> throughout; no sensitive data in console output |
|
||||
| 9. Code Quality & Hygiene | 5 | 4 | — | No eval; one unusual Blob dynamic import (not exploitable) |
|
||||
| 10. Infrastructure & Deployment | 3 | 2 | — | Nginx runs as root; no HSTS; CI uses pinned action versions |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -87,29 +89,31 @@ MetaScrub has a genuinely strong privacy and security posture for a client-side-
|
|||
|
||||
### Medium Issues
|
||||
|
||||
**1. devDependency critical/high vulnerabilities — `minimist` prototype pollution, `ansi-regex` ReDoS**
|
||||
*(All three medium-severity items at audit time have been resolved. See "Resolved Findings" below.)*
|
||||
|
||||
- Severity: MEDIUM (devDependencies only; not in production bundle)
|
||||
- Location: `package.json` — `madge` → `minimist` (critical, npm advisory 1097678), `@capacitor/cli` → `ansi-regex` (high, npm advisory 1094092, three paths)
|
||||
- Description: `yarn audit` reports 42 vulnerabilities: 2 critical (prototype pollution in `minimist < 1.2.6` via `madge > dependency-tree > precinct`), 21 high (ReDoS in `ansi-regex < 5.0.1` via `@capacitor/cli`), 19 moderate. None of these packages ship to the browser bundle. However, the prototype pollution in `minimist` runs during `yarn check:deps` in CI — if untrusted input ever reaches that path, `Object.prototype` could be poisoned in the same Node.js process that runs the build.
|
||||
- Impact: CI build process potentially affected; no user impact in production.
|
||||
- Fix: Upgrade `madge` to a version pulling in `minimist ≥ 1.2.6` and `@capacitor/cli` to a version pulling in `ansi-regex ≥ 5.0.1`. Wire Dependabot or Renovate to catch future advisories automatically.
|
||||
---
|
||||
|
||||
**2. No Dependabot / SCA wired into CI**
|
||||
### Resolved Findings *(shipped 2026-05-23)*
|
||||
|
||||
- Severity: MEDIUM
|
||||
- Location: `.github/workflows/ci.yml` — no security scanning step
|
||||
- Description: The CI pipeline runs lint, typecheck, vitest, and e2e but has no automated dependency vulnerability scanning. New CVEs against production dependencies (`react`, `pdf-lib`, `jszip`, `@ffmpeg/core`, `@uswriting/exiftool`) would not be caught until a developer manually runs `yarn audit`.
|
||||
- Impact: Silent accumulation of known vulnerabilities in production deps between audit runs.
|
||||
- Fix: Add `yarn audit --level high` as a failing CI step, or enable Dependabot/Renovate security alerts.
|
||||
**✅ devDependency critical/high vulnerabilities — RESOLVED in PR #196 (commit `e35f8aa`)**
|
||||
|
||||
**3. `style-src 'unsafe-inline'` in all production CSP policies**
|
||||
- Original: 42 vulnerabilities (2 critical `minimist` prototype pollution via `madge`, 21 high `ansi-regex` ReDoS via `@capacitor/cli`, 19 moderate).
|
||||
- Fix shipped: `@capacitor/cli` upgraded to `^7.6.5`, `vite` upgraded to `^7.3.3`, and `yarn resolutions` forcing patched transitive versions for `minimist`, `ansi-regex`, `rollup`, `picomatch`, `postcss`, and `brace-expansion`.
|
||||
- Verified: `yarn audit` now reports **0 findings**.
|
||||
|
||||
- Severity: MEDIUM
|
||||
- Location: `vite.config.web.ts:38`, `nginx.conf:26`, `public/_headers:10`
|
||||
- Description: All three CSP enforcement layers include `style-src 'self' 'unsafe-inline'`. While the strict `script-src 'self' 'wasm-unsafe-eval'` (no `unsafe-inline` for scripts in production) closes the primary XSS vector, `unsafe-inline` for styles allows CSS injection if XSS were achieved via another mechanism. CSS injection can exfiltrate attribute values, render malicious UI overlays, or read DOM content.
|
||||
- Impact: In a hypothetical XSS scenario, CSS injection amplifies impact to data exfiltration and UI spoofing. React's auto-escaping makes XSS in this app very unlikely, so the practical risk is low.
|
||||
- Fix: Audit which components use inline styles; migrate to CSS custom properties or class toggles. Then tighten CSP to `style-src 'self'` across `vite.config.web.ts`, `nginx.conf`, and `public/_headers`.
|
||||
**✅ No Dependabot / SCA wired into CI — RESOLVED in PR #196 (commit `e35f8aa`)**
|
||||
|
||||
- Fix shipped: `yarn audit --level high` added as a failing step in the CI `test` job (`.github/workflows/ci.yml`). New `high`-or-`critical` advisories will fail PR checks automatically.
|
||||
|
||||
**✅ `style-src 'unsafe-inline'` in all production CSP policies — RESOLVED in PR #197**
|
||||
|
||||
- Original: All three CSP enforcement layers included `style-src 'self' 'unsafe-inline'`.
|
||||
- Fix shipped:
|
||||
- `ErrorExpansion.tsx`: two static inline styles moved to BEM classes (`.file-table__error-text--copyable`, `.file-table__copy-hint`).
|
||||
- `SegmentedControl.tsx`: dynamic `transform` migrated to a CSS custom property (`--ec-segment-offset`) set via `useLayoutEffect` + `ref.style.setProperty` — a CSSOM call, not an inline `style` attribute, so no `unsafe-inline` needed.
|
||||
- `vite.config.web.ts`: production `styleSrc` is now `'self'` (dev retains `'unsafe-inline'` for Vite HMR).
|
||||
- `nginx.conf` + `public/_headers`: both server-level CSP headers updated to `style-src 'self'`.
|
||||
- Verified: production build's CSP meta tag emits `style-src 'self'` with no `unsafe-inline`.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -140,16 +144,16 @@ MetaScrub has a genuinely strong privacy and security posture for a client-side-
|
|||
|
||||
### Remediation Plan
|
||||
|
||||
| Priority | Action | Effort |
|
||||
|---|---|---|
|
||||
| 1 | Replace `.env` with password-manager retrieval for APK signing secret | 1–2 h |
|
||||
| 2 | Wire `yarn audit --level high` into CI as a failing gate | 30 min |
|
||||
| 3 | Upgrade `madge` and `@capacitor/cli` to resolve critical/high advisory chains | 1 h |
|
||||
| 4 | Tighten `style-src` — remove `'unsafe-inline'` from all CSP policies | 2–4 h |
|
||||
| 5 | Add HSTS header to `nginx.conf` (behind TLS guard / comment) | 15 min |
|
||||
| 6 | Tighten Capacitor `config.xml` to `<access origin="https://localhost/" />` | 5 min |
|
||||
| 7 | Run rootless nginx in `Dockerfile` (port 8080, `USER nginx`) | 30 min |
|
||||
| 8 | Add sha256 verification for `commandlinetools-linux-…_latest.zip` in Android builder Dockerfile | 30 min |
|
||||
| Priority | Action | Effort | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | Replace `.env` with password-manager retrieval for APK signing secret | 1–2 h | ⏳ open |
|
||||
| 2 | Wire `yarn audit --level high` into CI as a failing gate | 30 min | ✅ shipped 2026-05-23 (PR #196) |
|
||||
| 3 | Upgrade `madge` and `@capacitor/cli` to resolve critical/high advisory chains | 1 h | ✅ shipped 2026-05-23 (PR #196 — 42 → 0 findings) |
|
||||
| 4 | Tighten `style-src` — remove `'unsafe-inline'` from all CSP policies | 2–4 h | ✅ shipped 2026-05-23 (PR #197) |
|
||||
| 5 | Add HSTS header to `nginx.conf` (behind TLS guard / comment) | 15 min | ⏳ open |
|
||||
| 6 | Tighten Capacitor `config.xml` to `<access origin="https://localhost/" />` | 5 min | ⏳ open |
|
||||
| 7 | Run rootless nginx in `Dockerfile` (port 8080, `USER nginx`) | 30 min | ⏳ open |
|
||||
| 8 | Add sha256 verification for `commandlinetools-linux-…_latest.zip` in Android builder Dockerfile | 30 min | ⏳ open |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -157,7 +161,8 @@ MetaScrub has a genuinely strong privacy and security posture for a client-side-
|
|||
|
||||
A real-time SCA tool (Snyk, Dependabot, OSV-Scanner, `yarn npm audit`, etc.) should be run to catch CVEs published after my training cutoff. Versions flagged from `yarn audit` output (run 2026-05-22):
|
||||
|
||||
- `minimist < 1.2.6` — Prototype Pollution (critical) — via `madge > dependency-tree > precinct` (two paths). Advisory: npm/1097678.
|
||||
- `ansi-regex < 5.0.1` — Inefficient RegExp Complexity / ReDoS (high) — via `@capacitor/cli` (three paths). Advisory: npm/1094092.
|
||||
- `brace-expansion` (moderate) — Large numeric range defeats DoS protection — via `madge > precinct > detective-vue2 > minimatch`. Advisory: npm/1119088.
|
||||
- All flagged packages are devDependencies; none reach the production browser bundle.
|
||||
- `minimist < 1.2.6` — Prototype Pollution (critical) — via `madge > dependency-tree > precinct` (two paths). Advisory: npm/1097678. ✅ Resolved 2026-05-23 (PR #196).
|
||||
- `ansi-regex < 5.0.1` — Inefficient RegExp Complexity / ReDoS (high) — via `@capacitor/cli` (three paths). Advisory: npm/1094092. ✅ Resolved 2026-05-23 (PR #196).
|
||||
- `brace-expansion` (moderate) — Large numeric range defeats DoS protection — via `madge > precinct > detective-vue2 > minimatch`. Advisory: npm/1119088. ✅ Resolved 2026-05-23 (PR #196).
|
||||
- All flagged packages were devDependencies; none reached the production browser bundle.
|
||||
- `yarn audit` post-fix (2026-05-23): **0 findings**.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue