Skip to content

Security audit β€” 2026-06-10#46

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

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

Conversation

@versila22

Copy link
Copy Markdown
Owner

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

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

Findings

Sev Cat Title Location
Critical SAST Hardcoded Cloudflare R2 credentials in git history backend/scripts/_archive/migrate_local_to_r2.py:11-12
Critical SAST vitest CVSS 9.8 β€” arbitrary file read/exec when UI server running (GHSA-5xrq-8626-4rwp) package.json (vitest ~3.2.4)
High SAST JWT access token stored in sessionStorage (XSS-accessible) β€” Safari cross-origin fallback src/lib/api.ts:44-53
High SAST Seed data contains hardcoded default passwords (Admin1234!, Password1!) backend/app/main.py:54-62
High DAST react-router open redirect via // prefix (GHSA-2j2x-hqr9-3h42) β€” react-router-dom ~6.30.1 package.json
High SAST X-Forwarded-For not trusted-proxy-validated β€” rate limit bypass via header spoofing backend/app/limiting.py:14-16
Medium DAST /health/migrations leaks traceback + DB URL prefix, unauthenticated backend/app/main.py:224-238
Medium Infra nginx /assets/ block drops all security headers (add_header inheritance gap) nginx.conf
Medium DAST SameSite=None cookies β€” CSRF protection disabled, relies solely on CORS backend/app/utils/security.py:107-129
Medium SAST No max-size on photo data-URI upload β€” potential DB bloat / DoS backend/app/routers/members.py:336-356
Medium SAST Archived script reset commission accounts to weak single-word passwords backend/scripts/_archive/reset_passwords.py:10-16
Medium Infra HSTS missing preload directive nginx.conf
Medium Infra Let's Encrypt cert expires 2026-07-10 β€” verify auto-renewal is monitored limaimpro.duckdns.org:443
Low SAST api.ts.orig (localStorage token storage) committed to repo src/lib/api.ts.orig
Low SAST CORS default origin includes lovable.app β€” unintended cross-origin credential acceptance backend/app/config.py:37
Low SAST react-markdown used without html sanitization β€” safe now; guard against future rehype-raw src/
Low Infra Sentry DSN baked into bundle (VITE_SENTRY_DSN) β€” fake event injection possible vite.config.ts
Low Infra img-src https: in CSP is overly permissive (wildcard HTTPS origin) nginx.conf

Top 3 fixes

  1. Rotate R2 credentials β€” Revoke 85ac3f95ea5bb38cb2a4575909d12cae in Cloudflare dashboard immediately; purge from git history with git filter-repo
  2. Update vulnerable deps β€” npm update vitest react-router-dom (vitest β‰₯3.2.6, react-router-dom β‰₯6.30.4)
  3. Fix rate limiter trusted proxy β€” Use X-Real-IP or last IP in X-Forwarded-For chain rather than first (attacker-controlled) value

Evidence (Critical/High only)

C1 β€” R2 credentials in source

  • Location: backend/scripts/_archive/migrate_local_to_r2.py:11-12
  • Snippet: aws_access_key_id="85ac3f95ea5bb38cb2a4575909d12cae", aws_secret_access_key="efaf5aab9b029..."
  • Impact: Full read/write access to R2 bucket (member profile photos) if repo is leaked or VPS is compromised
  • Fix: Rotate creds in Cloudflare dashboard; run git filter-repo --path backend/scripts/_archive/migrate_local_to_r2.py --invert-paths and force-push all remotes

C2 β€” vitest GHSA-5xrq-8626-4rwp (CVSS 9.8)

  • Location: package.json β€” vitest ~3.2.4 (fix: β‰₯3.2.6)
  • Snippet: "vitest": "^3.2.4" β€” missing auth check allows arbitrary file read/exec when UI server is listening
  • Impact: Unauthenticated remote code execution on any machine running vitest --ui (CI runners, developer machines)
  • Fix: npm update vitest

H1 β€” JWT in sessionStorage

  • Location: src/lib/api.ts:44-53, src/contexts/AuthContext.tsx:74-77
  • Snippet: sessionStorage.setItem(_SESSION_KEY, token) β€” bearer token stored as Safari cross-origin fallback
  • Impact: Any XSS on the page steals the token β†’ full account takeover; httpOnly cookie path is safe
  • Fix: Evaluate if Safari fallback is still needed; if yes, tighten CSP and use short TTL + server-side revocation on logout

H2 β€” Hardcoded seed passwords

  • Location: backend/app/main.py:54-62
  • Snippet: "password": "Admin1234!" (admin), "password": "Password1!" (8 members)
  • Impact: If production DB was seeded and passwords never changed, admin account is trivially compromised
  • Fix: Audit all production seed accounts; remove passwords from seed data; use activation flow or random first-run passwords

H3 β€” react-router open redirect (GHSA-2j2x-hqr9-3h42)

  • Location: package.json β€” react-router-dom ~6.30.1 (fix: β‰₯6.30.4)
  • Snippet: Redirect to //attacker.example path treated as protocol-relative URL by affected versions
  • Impact: Phishing via crafted ?next=//attacker.example links if any app flow reads redirect target from query params
  • Fix: npm update react-router-dom

H4 β€” Rate limit X-Forwarded-For spoofing

  • Location: backend/app/limiting.py:14-16
  • Snippet: X-Forwarded-For read without trusted-proxy validation (first value is attacker-controlled)
  • Impact: Bypass per-IP rate limits on login (5/min) and forgot-password (3/min) β†’ enables credential stuffing
  • Fix: Trust only the IP injected by Railway's proxy; use X-Real-IP or last hop in X-Forwarded-For

Verified safe

  • No XSS sinks (dangerouslySetInnerHTML, innerHTML=, eval, document.write) in src/
  • No postMessage origin confusion found
  • No prototype pollution surface (no lodash, no unvalidated spread on user input)
  • TLS 1.0/1.1 disabled; TLS 1.2 + 1.3 enabled; cert valid until 2026-07-10
  • Sensitive files (.env, .git/config, etc.) all return 403
  • CORS does not reflect attacker origin with credentials
  • Nginx CSP, X-Frame-Options, X-Content-Type-Options, HSTS present in main server block
  • httpOnly cookies used as primary auth mechanism (sessionStorage only as Safari fallback)

Needs server-side verification

  • Whether production DB admin/seed accounts have had default passwords changed
  • Whether commission account passwords (ca, spectacle, comprog, comcom, comform) are still set to weak values
  • Whether Railway proxy sets X-Real-IP reliably (affects H4 fix approach)
  • Whether Traefik auto-renewal is active and monitored for the Let's Encrypt cert
  • Whether Vitest UI server is ever run in CI or exposed to network (affects C2 exploitability)

Tools

ran=npm-audit, grep-secrets, curl-headers, curl-cors, curl-sensitive-files, openssl-tls; skipped=none


Generated by Claude Code

…-05-20)

No prior reports to clean up (first run).
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