Skip to content

Fix Vimm path traversal, truncated-download corruption, and Prowlarr query escaping - #9

Merged
JeremiahM37 merged 2 commits into
mainfrom
fix/vimm-traversal-partial-downloads-query-escape
Jul 14, 2026
Merged

Fix Vimm path traversal, truncated-download corruption, and Prowlarr query escaping#9
JeremiahM37 merged 2 commits into
mainfrom
fix/vimm-traversal-partial-downloads-query-escape

Conversation

@JeremiahM37

Copy link
Copy Markdown
Owner

What & why

Three real bugs found while auditing the download and search paths — all verified against current main, self-contained, and covered by tests. The download-path issues are the sharp ones: PR #8's bug-sweep fixed them for the DDL path but two sibling paths were missed.

1. Path traversal in the Vimm download (security)

downloadVimmGame joined the server-supplied Content-Disposition filename straight onto the staging dir (filepath.Join(destPath, filename)). A malicious or MITM'd Vimm response with filename="../../.." could write outside the staging directory. The DDL path already defends against this with sanitizeFilename + safeChild (added in #8) — this applies the same guard to Vimm.

2. Truncated downloads reported as complete (reliability / corruption)

Both the Vimm and DDL copy loops discarded the f.Write error and returned success without checking downloaded == Content-Length. A dropped connection or full disk left a partial .7z that was then handed to the scan/organize pipeline and landed in the library as a "complete" game. Now: check the write error, treat a non-EOF read error as failure, verify the byte count against Content-Length, and delete the partial file on failure.

3. Broken Prowlarr query escaping (correctness)

queryEscape only replaced spaces and &, so any title containing ?, #, %, or + corrupted the query string and returned wrong/empty results — e.g. "Who Wants to Be a Millionaire?", "R.B.I. Baseball", "C++". Replaced with url.QueryEscape.

Validation

  • go build ./..., go vet ./..., gofmt clean
  • go test ./... — all 17 packages pass
  • New TestDownloadDDLTruncatedDownloadIsError (partial-download guard) and TestQueryEscapingRoundTrips (special-character round-trip regression)

downloadVimmGame joined the server-supplied Content-Disposition filename
straight onto the staging dir, so a malicious or MITM'd Vimm response with
filename="../../.." could write outside it. The sibling DDL path already
guards this with sanitizeFilename + safeChild (PR #8); apply the same to
Vimm.

Both copy loops also discarded the f.Write error and returned success
without checking downloaded == Content-Length, so a dropped connection or
full disk passed a truncated archive to the scan/organize pipeline as a
complete game. Check the write error, treat a non-EOF read error as
failure, verify the byte count, and delete the partial file on failure.

Adds TestDownloadDDLTruncatedDownloadIsError.
The hand-rolled queryEscape only replaced spaces and '&', so any game
title containing '?', '#', '%' or '+' corrupted the query string and
returned wrong or empty results (e.g. "...Millionaire?", "R.B.I.
Baseball", "C++"). Replace it with url.QueryEscape and drop the helper.

Replaces the old escaper's unit test with a round-trip regression test
over the previously-broken characters.
@JeremiahM37 JeremiahM37 self-assigned this Jul 14, 2026
@JeremiahM37
JeremiahM37 merged commit a983768 into main Jul 14, 2026
5 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