Skip to content

Security audit β€” 2026-06-26#75

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

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

Conversation

@versila22

Copy link
Copy Markdown
Owner

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

Probed URL: https://limaimpro.duckdns.org/
Stack: React 18 + Vite 7 / npm (bun.lock also present) / PWA=yes (vite-plugin-pwa, autoUpdate)
Counts: Critical=1 High=3 Medium=2 Low=2 Info=3

Findings

Sev Cat Title Location
Critical SAST Seed admin account with hardcoded password runs on every startup (incl. production) backend/app/main.py:53-135
High SAST JWT/Refresh token uses well-known default secret (insecure_dev_secret_change_me) with no startup guard in dev backend/app/config.py:10
High SAST Bearer token stored in sessionStorage (XSS-reachable) as Safari workaround src/lib/api.ts:42-53
High SCA vitest Critical (CVSS 9.8): arbitrary file read/exec when Vitest UI server is listening package.json / GHSA-5xrq-8626-4rwp
Medium SCA 5 High npm vulns unfixed: serialize-javascript RCE, @babel/plugin-transform-modules-systemjs code injection, fast-uri path traversal/host confusion, undici HTTP header injection + cookie bypass package.json
Medium SAST .env.production and src/lib/api.ts.orig committed to git (production API URL + old token-in-localStorage code leak) .env.production, src/lib/api.ts.orig
Low PWA Service worker caches all **/*.{js,css,html} with no exclusion of auth routes; stale authenticated UI could be served offline vite.config.ts:workbox.globPatterns
Low Infra TLS cert expires 2026-07-26 (30-day Let's Encrypt); no HSTS preload TLS cert / notAfter=Jul 26 03:04:00 2026 GMT
Info DAST Live site returned 403 Forbidden for all probes β€” HTTP headers, CORS, sensitive file enumeration not verifiable from audit environment https://limaimpro.duckdns.org/
Info SAST dangerouslySetInnerHTML in chart.tsx injects developer-controlled CSS custom properties (not user input) β€” low exploitability src/components/ui/chart.tsx:70
Info SAST react-markdown used without rehype-sanitize; safe as long as content comes from API, not user-supplied raw HTML src/components/cabaret/PlanPreview.tsx:98

Top 3 fixes

  1. Seed account in production β€” Gate _ensure_seed_data() behind if settings.is_development: and rotate admin@lima-impro.fr password immediately on production DB.
  2. JWT default secret β€” The model_validator already blocks production startup when APP_ENV != development; confirm APP_ENV=production and a strong JWT_SECRET/REFRESH_JWT_SECRET are set in Railway env vars, then remove the weak default string from source.
  3. vitest Critical + High SCA chain β€” Run npm audit fix (overrides in package.json already handle serialize-javascript, fast-uri, and @babel/plugin-transform-modules-systemjs; bump vitest to >=3.x patched release).

Evidence (Critical/High only)

[Critical] Hardcoded seed admin β€” backend/app/main.py:53

{"email": "admin@lima-impro.fr", "app_role": "admin", "password": "Admin1234!", ...}

_ensure_seed_data() is called unconditionally on every startup. On a fresh production DB it creates a known admin credential. Impact: full admin takeover of production. Fix: wrap call in if settings.is_development: ....

[High] Default JWT secret β€” backend/app/config.py:10

DEFAULT_JWT_SECRET = "insecure_dev_secret_change_me"
JWT_SECRET: str = DEFAULT_JWT_SECRET

Guard only raises in APP_ENV != development; if env var is missing or misconfigured, tokens can be forged. Impact: authentication bypass. Fix: verify Railway JWT_SECRET env var is set; add secret-length validator (>=32 chars).

[High] sessionStorage Bearer token β€” src/lib/api.ts:42-53

const _SESSION_KEY = "lima_access_token";
export function setSessionToken(token: string): void {
  try { sessionStorage.setItem(_SESSION_KEY, token); } catch { /* ... */ }
}

Any XSS (including via a future vulnerable dependency) can exfiltrate the token. Impact: session hijack without cookie theft. Fix: consider short-lived tokens + PKCE-style refresh, or document accepted risk with monitoring.

[High] vitest GHSA-5xrq-8626-4rwp (CVSS 9.8)
Package: vitest (devDependency). Vitest UI server allows arbitrary file read/exec. Impact: CI/CD pipeline compromise if Vitest UI is exposed. Fix: npm audit fix or pin vitest >=3.x patched release.

Verified safe

  • No hardcoded secrets or API keys found in source files (secret scan clean).
  • No eval() calls found in source.
  • No open redirect patterns found in client routing.
  • No postMessage handlers without origin check (no postMessage usage found).
  • No lodash prototype pollution risk (lodash not used).
  • No client-side JWT decode/verify (tokens treated opaquely).
  • VITE_SENTRY_DSN and VITE_API_URL are the only VITE_* vars β€” no sensitive secrets baked into bundle.
  • CSP in nginx correctly sets script-src 'self' (no unsafe-eval/unsafe-inline for scripts).
  • TLS 1.0 and TLS 1.1 disabled; TLS 1.2 and 1.3 enabled.
  • TLS cert valid (issued 2026-06-26, expires 2026-07-26).
  • X-Frame-Options: DENY, X-Content-Type-Options: nosniff, HSTS, and Referrer-Policy headers present in nginx config.
  • FastAPI docs (/docs, /redoc) disabled in production via is_development guard.
  • dangerouslySetInnerHTML in chart.tsx uses only internal theme config (not user input).

Needs server-side verification

  • CORS response headers (live site unreachable from audit environment β€” 403 on all requests).
  • Whether admin@lima-impro.fr seed account actually exists on production DB (password change needed if it does).
  • Whether Railway env var JWT_SECRET is set to a strong value distinct from the source-code default.
  • Whether APP_ENV=production is set correctly in Railway deployment.
  • PWA service worker cache behavior on authenticated routes (cannot inspect deployed SW).

Tools

ran=npm-audit, grep-secret-scan, openssl-tls-dates, openssl-tls-protocols, source-file-analysis
skipped=curl-http-headers (403 proxy block), curl-cors-test (403 proxy block), curl-sensitive-file-probe (connection failed β€” all returned HTTP 000)


πŸ€– Generated with Claude Code

https://claude.ai/code/session_013HkXjCZ39ZcFtSDY27x6uL


Generated by Claude Code

…-06-05)

Adds automated security audit report for 2026-06-26.
Findings: Critical=1 (seed admin in prod), High=3 (JWT default secret,
sessionStorage token, vitest CVSS 9.8), Medium=2 (SCA chain, committed
.env.production + api.ts.orig), Low=2 (PWA cache, TLS cert expiry).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013HkXjCZ39ZcFtSDY27x6uL
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