Skip to content

fix(api): reject path traversal in external subtitle filename - #1385

Merged
revam merged 4 commits into
ShokoAnime:masterfrom
Foowy:security/file-controller-hardening
Jul 27, 2026
Merged

fix(api): reject path traversal in external subtitle filename#1385
revam merged 4 commits into
ShokoAnime:masterfrom
Foowy:security/file-controller-hardening

Conversation

@Foowy

@Foowy Foowy commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • GetExternalSubtitle (FileController) passed the raw filename route parameter straight into Path.Combine with no traversal/absolute-path check — an authenticated caller (or anonymous, if AllowAnonymousFileStreamingInAPIv3 is on) could read arbitrary files on the host via ../ sequences or a rooted path.
  • The first pass at a fix simply rejected any filename containing / or \ — but that also blocked legitimate subtitles living in a subfolder next to the video, while doing nothing to stop encoded traversal segments embedded elsewhere in the name. Replaced with a regex (PathTraversalPattern) that specifically rejects ./.. path segments, plus a whitelist check against the video's actual known external subtitle filenames (MediaInfo.TextStreams) — filename can now only ever resolve to a subtitle genuinely linked to that file, not just any traversal-free string.
  • SonarCloud flagged the traversal regex as an unbounded-ReDoS risk; added a 250ms match timeout, matching the convention already used by LogService's filter regex.
  • An earlier revision of this PR also added an AllowedSeries (restricted/parental-control profile) check to the file-streaming endpoints, since they were missing it unlike other endpoints in this controller — that was dropped to keep this PR scoped to the traversal fix only; it's a separate, lower-severity gap that can be addressed independently.

Found during a local security review of the file-streaming surface.

Test plan

  • dotnet build Shoko.Server.sln -c Release — 0 errors

Rebase history

  • 2026-07-27 02:48 UTC — rebased onto master @ a9126a417 (4 commits), now at 1f7d99355

@Foowy
Foowy marked this pull request as draft July 13, 2026 16:20
@Foowy Foowy changed the title fix(api): harden file-streaming endpoints against traversal and access-control bypass fix(api): reject path traversal in external subtitle filename Jul 13, 2026
@Foowy
Foowy marked this pull request as ready for review July 13, 2026 16:22
@Foowy

Foowy commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Purely security check, most users will not see this, but we might as well not be a weak point

Comment thread Shoko.Server/API/v3/Controllers/FileController.cs Outdated
Comment thread Shoko.Server/API/v3/Controllers/FileController.cs
@Foowy
Foowy marked this pull request as draft July 16, 2026 19:40
@Foowy
Foowy force-pushed the security/file-controller-hardening branch from d72f683 to c58aaa6 Compare July 18, 2026 16:36
@Foowy

Foowy commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Used a 250ms match timeout for PathTraversalPattern, matching the timing already used by LogService's _logFilterRegexMatchTimeout.

@Foowy
Foowy marked this pull request as ready for review July 18, 2026 18:58
Foowy added 4 commits July 27, 2026 02:42
…s-control bypass

`GetExternalSubtitle` passed the raw `filename` route parameter into
`Path.Combine` with no traversal or absolute-path check, allowing an
authenticated (or anonymous, if `AllowAnonymousFileStreamingInAPIv3` is
enabled) caller to read arbitrary files on the host via `../` sequences
or a rooted path. Reject any `filename` containing `/`, `\`, or equal
to `.`/`..` before combining paths.

`GetFileStreamInternal`, `GetFileStreamDirectory`, and
`GetExternalSubtitle` also had no `AllowedSeries` check, unlike other
endpoints in this controller — a restricted/parental-control user
account could stream video or subtitles for series outside their
allowed list. Added `IsSeriesAllowedForFile`, reusing the existing
`JMMUser.AllowedSeries` check.
…versal fix only

Scoped this PR down to the path-traversal fix in GetExternalSubtitle.
The AllowedSeries check only matters for installs using Shoko's
restricted/parental-control user profiles and isn't worth bundling
with the traversal fix.
…tles

The previous check rejected any `filename` containing `/` or `\`,
which also blocked legitimate subtitles living in a subfolder next to
the video, while doing nothing to stop encoded traversal segments
embedded elsewhere in the name. Replaced with a regex that rejects
`.` /`..` path segments specifically (`PathTraversalPattern`), and
added a whitelist check against the video's known external subtitle
filenames (`MediaInfo.TextStreams`) so `filename` can only resolve to
a subtitle actually linked to the file.
SonarCloud flagged the unbounded Regex constructor as a ReDoS risk.
250ms matches the timeout convention already used by LogService's
filter regex.
@Foowy
Foowy force-pushed the security/file-controller-hardening branch from 8ddbec9 to 1f7d993 Compare July 27, 2026 02:43
@sonarqubecloud

Copy link
Copy Markdown

@revam
revam merged commit 0ab9138 into ShokoAnime:master Jul 27, 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.

2 participants