Skip to content

Security audit β€” 2026-06-17#65

Open
versila22 wants to merge 1 commit into
mainfrom
security-audit-2026-06-17
Open

Security audit β€” 2026-06-17#65
versila22 wants to merge 1 commit into
mainfrom
security-audit-2026-06-17

Conversation

@versila22

Copy link
Copy Markdown
Owner

Pentest mini-report β€” lima-app β€” 2026-06-17

Probed URL: https://limaimpro.duckdns.org/
Stack: React 18 + Vite 7 / npm / PWA=yes (vite-plugin-pwa, workbox, autoUpdate)
Backend: FastAPI (Python) on Railway
Counts: Critical=1 High=3 Medium=2 Low=1 Info=3

Findings

Sev Cat Title Location
Critical DAST/Deps Vitest UI server β€” arbitrary file read/exec (GHSA-5xrq-8626-4rwp) package.json β€” vitest <3.2.6
High DAST/Deps @babel/plugin-transform-modules-systemjs β€” arbitrary code gen (GHSA-fv7c-fp4j-7gwp) package.json β€” <=7.29.3
High DAST/Deps serialize-javascript RCE via RegExp/Date (GHSA-5c6j-r48x-rmvq) package.json β€” <=7.0.2
High Infra JWT access token stored in sessionStorage (XSS-extractable) src/lib/api.ts:46-52, src/contexts/AuthContext.tsx:65
Medium Infra nginx /assets/ strips all security headers (add_header inheritance bug) nginx.conf:28-31
Medium SAST CSP style-src 'unsafe-inline' weakens XSS mitigation nginx.conf:15
Low Infra TLS cert expires 2026-07-17 β€” 30-day renewal window live cert
Info Infra HSTS missing preload flag nginx.conf:16
Info PWA Service worker NetworkFirst caches API responses up to 1 hour β€” stale auth possible vite.config.ts:71-82
Info DAST/Deps fast-uri path traversal + esbuild NTLM hash (dev-only indirect) package.json

Top 3 fixes

  1. Vitest critical β€” npm install vitest@latest --save-dev (upgrade to >=3.2.6)
  2. nginx security headers stripped from /assets/ β€” repeat all add_header security directives inside the /assets/ location block
  3. JWT in sessionStorage β€” store Safari fallback token in React in-memory state (ref) instead of sessionStorage

Evidence (Critical/High only)

Critical β€” Vitest <3.2.6 (GHSA-5xrq-8626-4rwp)

  • package.json: "vitest": "^3.2.4" β€” in vulnerable range <3.2.6
  • If Vitest UI server is exposed (dev/staging), attacker can read arbitrary files and execute code on host.
  • Fix: upgrade to vitest >=3.2.6.

High β€” @babel/plugin-transform-modules-systemjs (GHSA-fv7c-fp4j-7gwp)

  • package.json override: "@babel/plugin-transform-modules-systemjs": ">=7.27.0" β€” still in vulnerable range >=7.12.0 <=7.29.3.
  • Malicious build input can cause arbitrary code generation/execution in the CI/build environment.
  • Fix: tighten override to ">=7.29.4".

High β€” serialize-javascript RCE (GHSA-5c6j-r48x-rmvq)

  • package.json override: "serialize-javascript": ">=6.0.2" β€” too permissive, <=7.0.2 is vulnerable.
  • Serializing attacker-controlled RegExp/Date during build β†’ RCE in build environment.
  • Fix: tighten override to ">=7.0.3".

High β€” JWT in sessionStorage

  • src/lib/api.ts:46: sessionStorage.setItem("lima_access_token", token) written on every login.
  • Any XSS can sessionStorage.getItem("lima_access_token") β†’ 8-hour JWT exfil β†’ session hijack.
  • Fix: use React in-memory ref for Safari fallback; do not persist to Web Storage.

Verified safe

  • No hardcoded secrets/API keys in source (grep scan: 0 results)
  • No dangerouslySetInnerHTML, innerHTML, eval, document.write in React source
  • ReactMarkdown without rehype-raw β€” raw HTML escaped by default
  • No open redirect or unvalidated location.href patterns
  • No postMessage usage in app source
  • No prototype pollution patterns
  • JWT_SECRET validated at startup (startup fails on default value in non-dev)
  • Auth cookies: httponly=True, secure=True, samesite=none
  • Rate limiting: login 5/min, forgot-password 3/min, feedback 10/min
  • .env, .git/config, .git/HEAD, backup.zip, dump.sql β†’ all HTTP 403
  • TLS 1.0/1.1 disabled; TLS 1.2+1.3 enabled
  • CORS: explicit allowlist, no wildcard

Needs server-side verification

  • Confirm JWT_SECRET/REFRESH_JWT_SECRET are non-default on Railway production
  • Verify nginx header stripping for /assets/ on live responses (DAST blocked by Traefik host filter)
  • Confirm CORS_ORIGINS env var excludes localhost origins in production
  • Confirm Vitest UI server is not exposed on any internet-facing port
  • Confirm FRONTEND_URL (https://improv-cabaret-planner.lovable.app) CORS injection is intentional
  • Confirm VITE_SENTRY_DSN is injected as a secret build arg, not hardcoded

Tools

ran=npm-audit, curl-headers, curl-cors, curl-sensitive-files, openssl-cert-dates, openssl-tls-protos, grep-secrets, grep-xss-sinks, grep-storage, grep-postmessage, grep-prototype-pollution, manual-SAST; skipped=pnpm-audit (no pnpm-lock.yaml), authenticated-DAST (site 403 host_not_allowed β€” Traefik host filtering active)


Generated by Claude Code

…-05-27)

C=1 H=3 M=2 L=1 I=3
Critical: vitest <3.2.6 arbitrary file read/exec (GHSA-5xrq-8626-4rwp)
High: babel/plugin-transform-modules-systemjs RCE, serialize-javascript RCE, JWT in sessionStorage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNAS9mhajMnFCfLL5mtztv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant