Skip to content

fix(security): narrow alternate write root to a plugin temp subdir (R2-11) - #343

Merged
RicherTunes merged 1 commit into
mainfrom
fix/r2-11-narrow-temp-root
Jun 5, 2026
Merged

RicherTunes merged 1 commit into
mainfrom
fix/r2-11-narrow-temp-root

Conversation

@RicherTunes

Copy link
Copy Markdown
Owner

Round-2 review R2-11

IsOutputPathAllowed accepted any path under the system temp dir as a legitimate write root (besides the configured DownloadPath). %TEMP% is world-writable and shared across processes, so that allowed a caller-supplied outputPath to land anywhere in it.

Fix

Narrow the alternate root to a plugin-owned %TEMP%/tidalarr subdir (PluginTempRoot), and stage GetTempFilePath there so the legitimate staging path stays inside the allowed root. Containment stays canonical-form (PathTraversalGuard), so the sibling-prefix case %TEMP%/tidalarr_evil is refused — not just %TEMP%/other.

Tests

TDD: under-subdir accepted; elsewhere-in-%TEMP% and sibling-prefix rejected. 51 download-client tests green.

🤖 Generated with Claude Code

…a plugin subdir (R2-11)

IsOutputPathAllowed accepted any path under the system temp dir as a legitimate write
root (besides the configured DownloadPath). %TEMP% is world-writable and shared across
processes, so that allowed a caller-supplied outputPath to land anywhere in it. Narrow
the alternate root to a plugin-owned %TEMP%/tidalarr subdir (PluginTempRoot), and stage
GetTempFilePath there so the legitimate staging path stays inside the allowed root.

Containment stays canonical-form (PathTraversalGuard), so the sibling-prefix case
"%TEMP%/tidalarr_evil" is refused, not just "%TEMP%/other".

TDD: under-subdir accepted; elsewhere-in-%TEMP% and sibling-prefix rejected. 51 download
tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
/// not all of <c>%TEMP%</c> — is accepted as the alternate write root, so a caller-supplied path landing
/// elsewhere in the (world-writable, shared) temp dir is refused. Staging (<see cref="GetTempFilePath"/>)
/// writes here.</summary>
internal static string PluginTempRoot { get; } = Path.Combine(Path.GetTempPath(), "tidalarr");
return Path.Combine(Path.GetTempPath(), $"tidalarr_{safeName}{extension}");
// R2-11: stage inside the plugin-owned temp subdir (the only alternate write root IsOutputPathAllowed
// accepts) rather than directly in the shared %TEMP%.
return Path.Combine(PluginTempRoot, $"tidalarr_{safeName}{extension}");
@RicherTunes
RicherTunes merged commit 2277603 into main Jun 5, 2026
14 checks passed
@RicherTunes
RicherTunes deleted the fix/r2-11-narrow-temp-root branch June 5, 2026 18:01
RicherTunes added a commit that referenced this pull request Sep 7, 2026
Picks up Common #343 (smoke test review fixes).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

2 participants