From 002f559b9df9683e884df8f444ef6dd397c0ea55 Mon Sep 17 00:00:00 2001 From: 4gray Date: Sat, 18 Jul 2026 19:02:53 +0200 Subject: [PATCH] fix(logging): redact Xtream path credentials --- .../src/lib/redact-sensitive-data.spec.ts | 34 +++++++++++++++++++ .../logging/src/lib/redact-sensitive-data.ts | 16 +++++++++ 2 files changed, 50 insertions(+) diff --git a/libs/shared/logging/src/lib/redact-sensitive-data.spec.ts b/libs/shared/logging/src/lib/redact-sensitive-data.spec.ts index 4ca3b35c4..100977237 100644 --- a/libs/shared/logging/src/lib/redact-sensitive-data.spec.ts +++ b/libs/shared/logging/src/lib/redact-sensitive-data.spec.ts @@ -105,6 +105,40 @@ describe('redactSensitiveData', () => { expect(output).toContain('profile'); }); + it('redacts Xtream credentials in playback URL paths', () => { + const username = 'xtream-path-user-secret'; + const password = 'xtream-path-password-secret'; + const urls = [ + new URL( + `https://example.com/base/live/${username}/${password}/101.ts` + ), + new URL( + `https://example.com/movie/${username}/${password}/202.mkv` + ), + new URL( + `https://example.com/series/${username}/${password}/303.mp4` + ), + new URL( + `https://example.com/timeshift/${username}/${password}/60/2026-07-18:12-00/404.ts` + ), + ]; + const embedded = `Playback failed for https://example.com/live/${username}/${password}/505.m3u8`; + const ordinaryLiveUrl = 'https://example.com/live/channel.m3u8'; + + const output = serialized( + redactSensitiveData({ urls, embedded, ordinaryLiveUrl }) + ); + + expect(output).not.toContain(username); + expect(output).not.toContain(password); + expect(output).toContain('101.ts'); + expect(output).toContain('202.mkv'); + expect(output).toContain('303.mp4'); + expect(output).toContain('404.ts'); + expect(output).toContain('505.m3u8'); + expect(output).toContain(ordinaryLiveUrl); + }); + it('does not mutate input and safely bounds cycles, depth, arrays, objects, and strings', () => { const input: Record = { status: 'ok', diff --git a/libs/shared/logging/src/lib/redact-sensitive-data.ts b/libs/shared/logging/src/lib/redact-sensitive-data.ts index e1b994b6e..c476ded6d 100644 --- a/libs/shared/logging/src/lib/redact-sensitive-data.ts +++ b/libs/shared/logging/src/lib/redact-sensitive-data.ts @@ -37,6 +37,13 @@ const SENSITIVE_KEY_SUFFIXES = [ 'username', ]; +const XTREAM_CREDENTIAL_PATH_SEGMENTS = new Set([ + 'live', + 'movie', + 'series', + 'timeshift', +]); + export interface RedactionOptions { maxDepth?: number; maxArrayItems?: number; @@ -119,6 +126,15 @@ function redactUrl( redacted.password = REDACTED_VALUE; } + const pathSegments = redacted.pathname.split('/'); + for (let index = 0; index < pathSegments.length - 3; index += 1) { + if (XTREAM_CREDENTIAL_PATH_SEGMENTS.has(pathSegments[index])) { + pathSegments[index + 1] = REDACTED_VALUE; + pathSegments[index + 2] = REDACTED_VALUE; + } + } + redacted.pathname = pathSegments.join('/'); + const search = redactSearchParams( redacted.searchParams, sanitizeValue