# Security Vulnerability analysis and resolution status for posterg-website. > Based on security audit (2026-02-08). All items tracked below. --- ## Resolved ### Infrastructure / Deployment | # | Issue | Severity | Resolution | |---|-------|----------|------------| | 1 | No HTTPS — admin credentials exposed in transit | 🔴 CRITICAL | TLS terminated upstream by reverse proxy. nginx.conf doesn't need to handle TLS directly. | | 3 | Uploaded files stored inside webroot | 🟠 HIGH | Storage moved to `STORAGE_ROOT` (`/var/www/posterg/storage/`), defined in `config/bootstrap.php`. | | 4 | File path mismatch — media broken & insecure | 🟠 HIGH | DB paths now storage-relative. New `public/media.php` serves files safely. `memoire.php` and `search.php` use `/media.php?path=…`. Cover recording fixed. | | 5 | Rate limiter bypassed by IP spoofing (`X-Forwarded-For`) | 🟠 HIGH | `src/RateLimit.php` `getClientIdentifier()` uses `REMOTE_ADDR` only. | | 6 | `.htaccess` rules silently ignored by nginx | 🟠 HIGH | All rules ported to `nginx/posterg.conf`. See `nginx/HTACCESS_TO_NGINX.md`. | | 13 | Deprecated `X-XSS-Protection` header | 🔵 LOW | Removed from `nginx/posterg.conf`. | ### Frontend / Assets | # | Issue | Severity | Resolution | |---|-------|----------|------------| | 10 | CDN stylesheet without SRI | 🟡 MEDIUM | CDN will not be used in production. Self-hosted, eliminating supply-chain risk. | ### Code Quality / Defence in Depth | # | Issue | Severity | Resolution | |---|-------|----------|------------| | 14 | Missing `rel="noreferrer"` on external links | 🔵 LOW | `rel="noopener noreferrer"` applied in `public/admin/thanks.php`. | | 15 | Unescaped integer outputs | 🔵 LOW | Explicit `(int)` casts added in `public/index.php` and `public/search.php`. | | 16 | Redundant `DATABASE_PATH` constant | 🔵 LOW | Removed from `config/bootstrap.php`. | ### Admin Panel — Authentication & Sessions | # | Issue | Severity | Resolution | |---|-------|----------|------------| | 2 | No PHP-level authentication in admin | 🔴 CRITICAL | `src/AdminAuth.php` implements session guard with `password_verify` + `session_regenerate_id`. All admin files call `AdminAuth::requireLogin()`. Credentials in gitignored `config/admin_credentials.php`. No-op when constant absent (dev/cli-server). | | 8 | Session cookies not hardened | 🟡 MEDIUM | Resolved with #2. `AdminAuth::startSession()` sets `HttpOnly=true`, `SameSite=Strict`, `Secure=true` (off on cli-server), `Path=/admin`, `Lifetime=0`. | --- ## In Progress | # | Issue | Severity | Status | |---|-------|----------|--------| | 7 | LIKE wildcard injection in admin search | 🟡 MEDIUM | Public `Database::searchTheses()` escapes `%` and `_` correctly. Same pattern must be applied to admin search and any other raw LIKE queries. | --- ## Not Yet Implemented | # | Issue | Severity | Files | |---|-------|----------|-------| | 11 | Missing Content-Security-Policy on public pages | 🟡 MEDIUM | `nginx/posterg.conf` → add CSP header to main server block | | 9 | `error.log` in web-accessible path | 🟡 MEDIUM | `public/admin/actions/formulaire.php` → use absolute path outside webroot | | 12 | CSV import missing server-side MIME validation | 🟡 MEDIUM | `public/admin/import.php` → add `finfo` MIME check | --- ## Priority Order 1. ~~🔴 CRITICAL~~ — All done (items 1–2) 2. 🟡 **MEDIUM** — Items 7, 9, 11, 12 remaining 3. ~~🔵 LOW~~ — All done (items 13–16) --- ## Good Practices Already in Place - ✅ SQL injection: all queries use PDO prepared statements - ✅ XSS output: `htmlspecialchars()` on all user-controlled output - ✅ CSRF: tokens with `bin2hex(random_bytes(32))`, validated with `hash_equals()` - ✅ File upload: MIME type validated with `finfo` - ✅ Input validation: year, IDs, pagination cast to integers - ✅ LIKE wildcard escaping in public search (`Database::escapeLikeString`) --- *Last updated: 2026-02-08*