Skip to content

fix(security): harden hooks, watermark, ingest SSRF, and VOD raw (S-2..S-5)#26

Merged
ntt0601zcoder merged 1 commit into
mainfrom
fix/security-critical-high
Jun 15, 2026
Merged

fix(security): harden hooks, watermark, ingest SSRF, and VOD raw (S-2..S-5)#26
ntt0601zcoder merged 1 commit into
mainfrom
fix/security-critical-high

Conversation

@ntt0601zcoder

Copy link
Copy Markdown
Owner

Closes the remaining CRITICAL + HIGH security findings from the audit. Shared SSRF dial guard in new internal/netguard.

S-2 (CRITICAL) — arbitrary host-file write + SSRF via hooks

  • domain.Hook.Validate(fileRoot) now runs at the REST boundary (Create/Update) and the YAML path (shared), closing the zero-validation gap.
  • File hooks confined to hooks.file_root_dir (path containment, re-checked in deliverFile).
  • Webhook http.Clientnetguard: loopback + link-local/cloud-metadata blocked (no localhost-admin / IMDS pivot); internal webhooks still allowed.

S-3 (HIGH) — lavfi filtergraph injection via watermark font_color

  • ValidateFontColor rejects anything that isn't a plain color literal.
  • buildTextFilter single-quotes fontcolor; escapeLavfiArg now escapes single-quote too (also closes the fontfile/movie breakout).

S-4 (HIGH) — SSRF via ingest/pull input URLs

  • netguard dial-time IP guard on the HTTP-TS + HLS clients (resolved-IP → covers DNS-rebind, redirects, playlist-chosen hosts); cross-host credential-header strip.
  • Gated by ingestor.allow_private_targets (default off; link-local/metadata always blocked). Save-time URL speed-bump in the stream handler.

S-5 (HIGH) — arbitrary host-file read via VOD /raw

  • Raw serves only video-allowlisted files (404 otherwise).
  • ResolvePath resolves symlinks before the mount-boundary check; ValidateStorage refuses sensitive system dirs.

New config (backward-compatible defaults)

  • hooks.file_root_dir (default empty = legacy absolute-path-only; SSRF + REST-validation apply regardless).
  • ingestor.allow_private_targets (default false → private HTTP/HLS ingest blocked; UDP multicast / RTSP / RTMP / SRT unaffected).

Residuals (noted in the audit)

  • Hook file-containment is opt-in; a symlink inside the root is still followed.
  • RTSP/RTMP/SRT/UDP dials not yet IP-guarded at dial time (no body channel).

Tests

New netguard suite, TestHookValidate, TestValidateFontColor, TestValidateStorageRejectsSensitive, TestRegistry_ResolvePathRejectsSymlinkEscape + updated existing. go build, go vet, golangci-lint (0 issues), go test -race ./... all green.

…..S-5)

Address the remaining CRITICAL + HIGH findings from the audit.

- S-2 (hooks): validate hooks at the REST boundary via a shared
  domain.Hook.Validate (matching the YAML path, previously the only validated
  entry); confine file hooks to hooks.file_root_dir (path containment,
  re-checked at delivery); route the webhook HTTP client through the SSRF dial
  guard so loopback + link-local / cloud-metadata are blocked (internal
  webhooks still allowed).
- S-3 (watermark): reject non-literal font_color in domain validation and
  single-quote + escape it in the lavfi filtergraph; escapeLavfiArg now also
  escapes single quotes, closing the fontfile/movie breakout.
- S-4 (ingest SSRF): new internal/netguard dial-time IP guard on the HTTP-TS
  and HLS pull clients — runs on the resolved IP so it covers DNS-rebind,
  redirects, and playlist-chosen hosts — plus a cross-host credential-header
  strip. Gated by ingestor.allow_private_targets (default off; link-local /
  metadata always blocked). Save-time URL speed-bump in the stream handler.
- S-5 (VOD raw): serve only video-allowlisted files (404 otherwise), resolve
  symlinks before the mount-boundary check, and refuse mounting sensitive dirs.

New config: hooks.file_root_dir and ingestor.allow_private_targets, both with
backward-compatible defaults. Tests + audit notes included.
@ntt0601zcoder ntt0601zcoder merged commit a7bd232 into main Jun 15, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant