Skip to content

Security audit β€” 2026-06-09#45

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

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

Conversation

@versila22

Copy link
Copy Markdown
Owner

Pentest mini-report β€” versila22/lima-app β€” 2026-06-09

Probed URL: https://limaimpro.duckdns.org/
Stack: React 18 + Vite / npm / PWA=yes (vite-plugin-pwa, workbox, autoUpdate)
Counts: Critical=0 High=3 Medium=4 Low=3 Info=2

Findings

Sev Cat Title Location
High SAST JWT token stored in sessionStorage (Safari fallback) src/lib/api.ts:42-53
High SAST .orig backup file with localStorage token storage committed to git src/lib/api.ts.orig:22-33
High Infra react-router-dom open redirect via //-prefixed path (CVE GHSA-2j2x-hqr9-3h42) node_modules/react-router v6 <6.30.4
Medium SAST dangerouslySetInnerHTML injects CSS from chart config into DOM src/components/ui/chart.tsx:70
Medium PWA Service worker caches all JS/CSS/HTML including auth routes (NetworkFirst for API, but SW intercepts) vite.config.ts workbox globPatterns
Medium Infra CSP style-src 'unsafe-inline' weakens XSS mitigation nginx.conf:18
Medium Infra Dependency audit: serialize-javascript RCE in build toolchain (GHSA-5c6j-r48x-rmvq) node_modules/serialize-javascript (workbox-build dep)
Low SAST Sidebar state cookie set without Secure or SameSite flags src/components/ui/sidebar.tsx:68
Low Infra No Cache-Control: no-store on auth API responses β€” needs server-side check API backend
Low Infra .env.production and .env.development committed to git (contain VITE_API_URL only β€” no secrets currently, but sets bad precedent) .env.production, .env.development
Info Infra TLS 1.0/1.1 disabled, TLS 1.2+1.3 enabled, cert valid until 2026-07-09 limaimpro.duckdns.org:443
Info Infra vitest critical CVE (GHSA-5xrq-8626-4rwp) β€” devDependency only, not deployed package.json devDependencies

Top 3 fixes

  1. react-router open redirect β€” Upgrade react-router-dom to β‰₯6.30.4 (npm install react-router-dom@latest).
  2. sessionStorage JWT fallback β€” Evaluate removing the Safari fallback or scope it strictly; rotate tokens frequently and document the accepted risk.
  3. .orig file in git β€” git rm src/lib/api.ts.orig and purge from history with git filter-repo to remove the old localStorage token pattern.

Evidence (Critical/High only)

H1 β€” JWT in sessionStorage

  • Location: src/lib/api.ts:42-53, src/contexts/AuthContext.tsx:73-76
  • Snippet: const _SESSION_KEY = "lima_access_token"; sessionStorage.setItem(_SESSION_KEY, token);
  • Impact: Any same-origin JS (XSS, malicious extension) can steal the access token; XSS + sessionStorage = full auth compromise.
  • Fix: Prefer httpOnly cookies exclusively; remove sessionStorage fallback or gate it behind user-visible Safari warning.

H2 β€” .orig backup with localStorage token pattern committed

  • Location: src/lib/api.ts.orig:22-33 (tracked by git: confirmed via git ls-files)
  • Snippet: const TOKEN_KEY = "lima_token"; localStorage.getItem(TOKEN_KEY); localStorage.setItem(TOKEN_KEY, token);
  • Impact: Old insecure pattern (localStorage instead of httpOnly cookie) persists in repo history; token more persistent and broader-scope than sessionStorage.
  • Fix: git rm src/lib/api.ts.orig && git filter-repo --path src/lib/api.ts.orig --invert-paths

H3 β€” react-router open redirect

  • Location: node_modules/react-router <6.30.4 (GHSA-2j2x-hqr9-3h42)
  • Snippet: <Navigate to="//attacker.example" /> or useNavigate()("//attacker.example") β†’ browser reinterprets as protocol-relative URL.
  • Impact: Phishing redirect after login; attacker can construct login links that redirect users to a malicious site.
  • Fix: npm install react-router-dom@latest (β‰₯6.30.4).

Verified safe

  • No hardcoded secrets in committed files (.env.production contains only public VITE_API_URL, not keys)
  • CORS: explicit allowlist (limaimpro.duckdns.org, localhost variants) with allow_credentials=True β€” no wildcard reflection
  • HSTS enabled (max-age=31536000; includeSubDomains) on both nginx and backend middleware
  • X-Frame-Options: DENY and frame-ancestors 'none' in CSP β€” clickjacking protected
  • X-Content-Type-Options: nosniff present
  • TLS 1.0/1.1 disabled; TLS 1.2 and 1.3 only
  • Sensitive file probes (.env, .git/config, backup.zip) all return 403
  • dangerouslySetInnerHTML in chart.tsx uses only hardcoded dev-time config (CSS color strings), not server data
  • JWT_SECRET weak-default check enforced at startup in non-dev mode (validate_jwt_secret validator)
  • No VAPID private key in client bundle (no push notifications configured)
  • No eval() or document.write() in source
  • react-markdown used without rehype-raw β€” no HTML passthrough risk

Needs server-side verification

  • Cookie flags (HttpOnly, Secure, SameSite=Strict/Lax) on auth cookies set by FastAPI backend (Railway-hosted, not audited here)
  • Cache-Control: no-store on /auth/* and /api/* responses from backend
  • Rate-limiting effectiveness on /auth/login (slowapi present in backend, thresholds not reviewed)
  • Backend CSP header values (SecurityHeadersMiddleware sets default-src 'none' for API β€” verify in prod response)
  • Sentry DSN exposure: VITE_SENTRY_DSN baked into bundle at build time β€” confirm it is intentionally public or rotate if leaked

Tools

ran=npm-audit, curl-headers, curl-cors, curl-sensitive-file-probe, openssl-tls; skipped=none


Generated by Claude Code

…-05-19)

First automated pentest report. Findings: C=0 H=3 M=4 L=3 Info=2.
Top issues: react-router open redirect (H), JWT in sessionStorage Safari
fallback (H), .orig file with localStorage token pattern in git (H).
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