# Security remediation summary (2026-05)

## Fixes applied in code

| Area | Change |
|------|--------|
| API auth | `ApiAuthMiddleware` — JWT required on all `/api/v1/*` except login, setup, licensing, installer metadata |
| Defaults | `DEBUG=false`, `ENVIRONMENT=production`, `ALLOW_LEGACY_UNLICENSED=false` |
| Production boot | `validate_production_config()` — weak `SECRET_KEY` / DB password blocked |
| login-direct | Disabled unless `DEBUG` + `ENVIRONMENT` in development/local |
| CORS | Named origins only; no `*` with credentials |
| Errors | No stack traces in production 500 responses |
| OpenAPI | `/docs` disabled in production |
| Static | Removed duplicate `/static/{path}` handler (path traversal risk) |
| Debug routes | `/debug-static`, `/metrics` gated |
| Health | DB/Redis health no longer expose connection URLs |
| Password change | Requires auth + current password (self) or admin |
| User create | Admin-only |
| Installer ZIP | Optional `INSTALLER_DOWNLOAD_KEY` in production |
| Branch list | `login-branches` requires `company_code` in production |
| Branch scope | No longer disabled when `DEBUG=true` |

## Still recommended (follow-up)

- Re-add explicit `Depends(get_current_user)` on sensitive routes for defense in depth
- Rate-limit public licensing and login endpoints (nginx or middleware)
- Move `/api/v1/logs/*` behind admin role
- Restrict `/api/v1/system-health/update/trigger` (already admin in UI; verify API)
- Penetration test after Hetzner deploy
- Rotate `SECRET_KEY` if it was ever committed or used in production with default value

## Local development

Add to `.env`:

```env
DEBUG=true
ENVIRONMENT=development
ALLOW_LEGACY_UNLICENSED=true
```
