fix(security): push-endpoint SSRF guard + tmux name validation; document tail-file roots

- M7 (SSRF): add isSafePushEndpoint (https-only; reject internal/loopback/link-local/metadata IPs incl. IPv4-mapped); enforce in PushSubscribeSchema and re-check before webpush.sendNotification. + unit test.
- M1 (command injection): validate tmux session names with isValidMuxName in sessionExists, killSession, and reconcileSessions before they reach a shell call site.
- M5: keep the intentional /var/log + ~/logs log-tail roots (a tested feature) and document the wider read scope in docs/security-architecture.md section 5 instead of dropping it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arkon
2026-06-09 20:02:17 +02:00
co-authored by Claude Opus 4.8
parent d5f91e4cd7
commit b84438a0aa
8 changed files with 174 additions and 12 deletions
+6 -2
View File
@@ -8,7 +8,7 @@
*/
import { z } from 'zod';
import { SAFE_PATH_PATTERN } from '../utils/index.js';
import { SAFE_PATH_PATTERN, isSafePushEndpoint } from '../utils/index.js';
// ========== Path Validation ==========
@@ -531,7 +531,11 @@ export const RespawnEnableSchema = z.object({
/** POST /api/push/subscribe */
export const PushSubscribeSchema = z.object({
endpoint: z.string().url().max(2000),
endpoint: z
.string()
.url()
.max(2000)
.refine(isSafePushEndpoint, { message: 'endpoint must be an https URL to a public (non-internal) host' }),
keys: z.object({
p256dh: z.string().min(1).max(500),
auth: z.string().min(1).max(500),