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-21.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Pentest mini-report — versila22/lima-app — 2026-06-21

**Probed URL:** https://limaimpro.duckdns.org/
**Stack:** React 18 / Vite 7 / TypeScript / FastAPI (Python) / pnpm+npm / PWA=yes (VitePWA + Workbox autoUpdate)
**Counts:** Critical=0 High=0 Medium=2 Low=2 Info=1

## Findings

| Sev | Cat | Title | Location |
|---|---|---|---|
| Medium | DAST | CSP style-src unsafe-inline | nginx.conf:12 |
| Medium | SAST/PWA | JWT access token in sessionStorage (Safari fallback) | src/lib/api.ts:44-45 |
| Low | SCA | react-router open redirect via protocol-relative URL (v6.30.3 < 6.30.4) | package.json |
| Low | SCA | PostCSS XSS via unescaped </style> in CSS output (v8.5.9 < 8.5.10) | package.json |
| Info | SAST | dangerouslySetInnerHTML in chart style tag (CSS color config, not user input) | src/components/ui/chart.tsx:70 |

## Top 3 fixes
1. **CSP style-src unsafe-inline** — Replace `'unsafe-inline'` with a nonce or hash; Tailwind/Vite builds support hash-based CSP via vite-plugin-csp.
2. **react-router open redirect** — Upgrade react-router-dom to ≥6.30.4 (`npm update react-router-dom`).
3. **PostCSS XSS** — Upgrade postcss to ≥8.5.10 (`npm update postcss`); low exploitability (build-time only).

## Evidence (Critical/High only)
_No Critical or High findings._

## Verified safe
- No secrets or credentials committed to repo (grep: 0 matches)
- CORS uses explicit origin allowlist (`allow_origins=settings.CORS_ORIGINS`) with no reflection — not exploitable
- JWT_SECRET validated to non-default in any non-development `APP_ENV` (config.py:62-70)
- Rate limiting on auth endpoints: `@limiter.limit("5/minute")` (routers/auth.py:116, 213)
- Security headers on both layers: nginx (CSP, HSTS, X-Frame-Options, nosniff) and backend SecurityHeadersMiddleware
- TLS 1.0 disabled, TLS 1.1 disabled, TLS 1.2+1.3 enabled (cert valid 2026-07-21)
- httpOnly auth cookies with path-scoped refresh token (`/auth/refresh`)
- SameSite=None required for cross-origin frontend/backend architecture; mitigated by strict CORS allowlist (JSON API uses non-simple content-type triggering CORS preflight)
- No user-controlled URLs passed to `navigate()` — all calls use hardcoded paths
- PWA SW scope `/`, NetworkFirst API caching with 1h TTL and 50-entry cap — no auth route caching issue
- Sensitive paths (.env, .git/config, etc.) blocked by reverse proxy (HTTP 403)
- All HIGH/CRITICAL npm audit packages (vitest, vite, undici, fast-uri, babel) are dev=true; not in production bundle

## Needs server-side verification
- DAST header analysis blocked by execution environment network policy — full header set (CSP value, HSTS preload status) should be verified with: `curl -sI https://limaimpro.duckdns.org/`
- Confirm Railway backend sends `Strict-Transport-Security` header in production (SecurityHeadersMiddleware is present in code but should be validated live)
- Confirm sessionStorage token cleared on logout across all Safari code paths

## Tools
ran=npm-audit, grep-secrets, openssl-tls; skipped=pnpm-audit (not used), curl-headers (network policy blocks outbound HTTP to target hosts)
Loading