diff --git a/devdocs/modernization/SECURITY-REVIEW.md b/devdocs/modernization/SECURITY-REVIEW.md index 13369f74..96c668e6 100644 --- a/devdocs/modernization/SECURITY-REVIEW.md +++ b/devdocs/modernization/SECURITY-REVIEW.md @@ -347,6 +347,7 @@ first SuperUser login; at least warn in the UI and the manual. `POST license/lc` with body `"iaccepttheagreement"` records the EULA consent; the comment says "SuperUser only", but the route is anonymous. Legal rather than technical: the consent record does not prove who accepted. Fix: require SuperUser. +**John, 2026-10-24: accepted as is** (login is refused until consent is given, so consent can't require a login; requiring credentials in the request would need a client change). To be checked from a legal standpoint. ### F11 Anonymous API root page discloses licence details (pass 2) @@ -359,6 +360,7 @@ targets by version. Fix: show it only to logged-in users, or show the version on PBKDF2-HMAC-SHA512, 10,000 iterations, 32-byte random salt (`Hasher.cs`). Current guidance (OWASP) is 210,000 iterations for SHA-512. Only matters if the database or a backup leaks. Raising it needs re-hashing at next login (store the iteration count). Roadmap item, not 8.3.0. +**2026-10-24: later case, not 8.3.0** (John left it to the review). It only matters if the database or a backup leaks (online guessing is limited by case 4726); 210,000 iterations make each login, change and reset about 20 times more work, to be measured on a small droplet; it needs a schema change (iteration count per user) and re-hashing at each user's next login. ### Pass 3 overview: customer contact isolation @@ -508,6 +510,7 @@ this needs a leaked id. The browser runs with `--no-sandbox` (Chrome's own sandb browser bug reached through a template is not contained; Linux runs as `www-data`, Windows LAN as the logged-in user. Fix: owner check on job routes; consider enabling the sandbox where the platform allows. +**John, 2026-10-24:** owner check and template export in case 4727; Chrome's sandbox **accepted as off** (it often fails on Linux servers and can't run as root). The systemd options in F38 would contain the browser as a child of the service on hosted droplets. ### F23 Logo upload: any content type, served inline (pass 5, from code) @@ -548,6 +551,8 @@ translated text is ever rendered as HTML in the client is a pass 9 question. Fix - Customer contacts can attach files to any customer's service request (part of F14; fixed by the same ownership check). +**John, 2026-10-24:** `OverrideUserId` and the export download check in case 4727; the upload written to disk before the rights check is **accepted** (since case 4712 every login that reaches it is staff; a proper fix restructures the upload, a possible later case). + OK in this pass: attachments are served as downloads (`Content-Disposition: attachment`), stored under content-hash names in the attachments folder; batch move, batch delete and maintenance check rights; data import (`POST import`) checks create rights per type; there is no restore @@ -727,6 +732,8 @@ Fix: add the headers in the app (so every deployment gets them), with a CSP that client's own scripts; limit CORS to the server's own origin unless API users need more; consider Swagger UI for logged-in users only. +**John, 2026-10-24:** the safe headers (`nosniff`, `X-Frame-Options`, `Referrer-Policy`) in case 4727. Content-Security-Policy for the client: its own later case, it needs testing of the whole client. CORS: **accepted** as is (the token is a header, not a cookie; limiting origins could break browser-based API users). Swagger at `/api-docs`: **accepted** public (it is the API documentation). + ### F36 Listening on all interfaces, no firewall (pass 10, from code) Every `config.json` template (`lan-install-config.json`, `linux-server`, `linux-desktop`, the @@ -740,6 +747,7 @@ install also accepts connections from the whole network. Fix: hosted and Linux s templates bind `http://127.0.0.1:7575` when behind a proxy; the setup script enables `ufw` allowing only 22, 80 and 443; standalone binds to localhost; LAN stays on all interfaces (that is its purpose) and the manual recommends HTTPS through IIS for anything beyond the LAN. +**John, 2026-10-24:** standalone **left** on all interfaces (some users open it from another device; binding it to localhost would break them). Hosted: bind `127.0.0.1` in the `sockeye-client` setup script (to do there). `ufw`: not needed, every droplet has the restrictive cloud firewall. ### F37 Standalone PostgreSQL trusts local connections (pass 10, from code) @@ -767,6 +775,8 @@ prepared database, so it is not that short: accepted. superuser password. It is not built (`build-release.bat` lines are commented out) or documented; delete it or fix it before anyone uses it. +**John, 2026-10-24:** the `chmod` and the systemd sandboxing options go into the `sockeye-client` setup script (to do there; the systemd options need testing on a droplet so nothing that writes, such as logs, backups or the report browser download, is blocked). `dist/docker`: early development option, never offered: removed in case 4727. + OK in pass 10: the setup script generates a unique database password and JWT secret per droplet, stores them in `/root/ayanova-secrets.txt` (600), makes `config.json` 640 `root:www-data`, runs AyaNova as `www-data`, installs unattended upgrades, uses PGDG PostgreSQL on its default