Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions security/pentest-2026-06-23.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Pentest mini-report — versila22/lima-app — 2026-06-23

**Probed URL:** https://limaimpro.duckdns.org/
**Stack:** React 18 (Vite/SWC) + FastAPI (Railway) / npm / PWA=yes (workbox, autoUpdate)
**Counts:** Critical=0 High=0 Medium=2 Low=3 Info=2

## Findings

| Sev | Cat | Title | Location |
|---|---|---|---|
| Medium | SAST | Auth token stored in sessionStorage (Safari ITP workaround) | `src/lib/api.ts:45` |
| Medium | Infra | devDep npm vulns — vitest CVSS 9.8, vite, undici (6 high) | `package.json` / npm audit |
| Low | DAST | CSP `style-src 'unsafe-inline'` | `nginx.conf:26` |
| Low | SAST | react-router@6.30.3 same-origin open redirect (CWE-601) | `package.json` |
| Low | SAST | Sidebar cookie missing `Secure;SameSite` flags | `src/components/ui/sidebar.tsx:68` |
| Info | SAST | Default FRONTEND_URL (lovable.app) auto-appended to CORS whitelist | `backend/app/config.py:35,85-87` |
| Info | DAST | HTTP response headers unverified (egress blocked in audit env) | `https://limaimpro.duckdns.org/` |

## Top 3 fixes
1. **devDep vulns** — `npm update vitest vite undici` and pin to patched versions in package.json
2. **sessionStorage auth token** — prefer httpOnly-only cookie flow; reduce `ACCESS_TOKEN_EXPIRE_MINUTES` (currently 480 min) if sessionStorage fallback is retained
3. **CSP unsafe-inline styles** — replace `style-src 'unsafe-inline'` with content hash or nonce in nginx.conf

## Evidence (Critical/High only)

_No Critical or High findings this run._

## Verified safe
- No XSS sinks: `dangerouslySetInnerHTML`, `innerHTML`, `eval` — none found in `src/`
- No hardcoded secrets in client source (VITE_API_URL only, not sensitive)
- Nginx serves HSTS (max-age=31536000), X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy, Permissions-Policy per `nginx.conf`
- Backend CORS uses explicit whitelist (`allow_origins=settings.CORS_ORIGINS`) with `allow_credentials=True` — no wildcard reflection
- PWA SW scope `/`; API caching uses NetworkFirst; auth tokens not in localStorage
- TLS 1.0/1.1 disabled; TLS 1.2 + 1.3 only
- No prototype pollution surface (no Object.assign/lodash.merge on user input)
- No postMessage listeners without origin validation

## Needs server-side verification
- CORS reflection on production Railway API (`https://api-production-e15b.up.railway.app`) — verify `Access-Control-Allow-Origin` is never reflected from request `Origin`
- Actual HTTP response headers from limaimpro.duckdns.org (nginx.conf has correct config, but deployment must be confirmed)
- `FRONTEND_URL` and `JWT_SECRET` env vars overridden in Railway environment (defaults are `lovable.app` URL and `insecure_dev_secret_change_me`)
- Sensitive path probing (`.env`, `.git/config`) — all returned 403 from audit env proxy, not from actual server

## Tools
ran=npm-audit, grep-secrets, openssl-tls; skipped=pnpm-audit (not installed), DAST-curl (egress policy blocks limaimpro.duckdns.org and railway API)
Loading