mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-09 21:43:05 +09:00
Plan 73 item 3. The quick-access rail links the local target at /etc/nginx, but /etc was never in ALLOWED_ROOTS, so the shortcut returned 403 for every user including admins -- a dead button, and our own regression: it shipped after the review that flagged the surrounding SSL story. /etc/nginx is now an allowed root, but browse-only. The panel generates those vhosts itself, so a hand edit is silently overwritten on the next domain change, and a writable /etc/nginx would hand anyone holding files.write a root-owned config that the panel itself reloads -- a much larger grant than "let me look at the effective config", which is all the shortcut is for. READ_ONLY_ROOTS is a second tier under ALLOWED_ROOTS rather than a special case for this one path: is_path_writable() = allowed AND not read-only, and every mutating entry point now gates on it instead of on is_path_allowed, so adding a future root to the list is enough to make the whole write surface refuse it. Both comparisons resolve with realpath first, so a symlink planted in a writable root cannot launder a write into the subtree. copy is deliberately asymmetric -- copying a vhost out to keep only reads the source, so only the destination is gated -- while move removes its source and therefore checks both ends. The upload endpoint repeats the check because it writes to disk directly instead of going through FileService's methods. Only this subtree is opened, not /etc: /etc/passwd and /etc/shadow stay denied, and the panel-internal PROTECTED_ROOTS exclusion is untouched (GHSA-rm3m-9mvw-68fh). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>