YT ▶ PLEX Under Review: One Blank Page, Four Hardening Passes, a Test Suite
Why: With the feature set settling (playlists, uploads, direct file links, YouTube sign-in), Damien asked for fresh eyes before more work, so I sent an independent review agent through the code and a private running copy.
The review came back broadly positive: output is XSS-safe, file names can't escape their folders, and moves check for conflicts first. It still found 1 critical, 3 high, 7 medium and 8 low issues. All were fixed today in four commits, each with tests, and the published release was rebuilt. Source is now a local Git repo at /home/plex/yt-plex (branch main, no remote).
1. The critical one: a failed lookup blanked Home
A variable was read two lines before it was set, so any permanently failing link (private or deleted video) made /api/state return 500, and the page rendered as an empty Home with no error. It was introduced the same day and was live, and in the published release, for a few hours. It's fixed, and a test now fails against the old code.
2. Security
- Playlist and feed entries are untrusted: only
http(s)links are accepted,--separates yt-dlp's options from every URL, FFmpeg may only fetch web addresses, and the page renders nothing but http(s) links. - Login: a per-address lockout after 5 failures in 15 minutes (behind NPM this relies on the forwarded address), with password checks run off the event loop.
- Sessions carry an epoch, so a password change or reset and the new "Sign out other devices" button revoke other sessions. The cookie gets
Securewhenever it's served over HTTPS. - Cross-site: API writes need the app's own
X-YTPheader and a matching Origin. This matters because every*.skyhouse.devsubdomain counts as "same-site" for cookies. - The clipboard feature now offers links instead of adding them silently, and the password-reset marker is an HMAC rather than a bare SHA-256.
3. Media-file safety
- Renaming a saved movie moves its whole folder, so posters, extras and other subtitles come along. The only file yt-plex ever deletes is a thumbnail it made itself. Previously a user-added
Title (Year).jpgposter could be deleted. - Every row removal clears its staging download, and startup sweeps orphans.
- Library checks run in parallel with a 4-second limit, so a hung NFS/SMB mount can't freeze the app.
- Names are limited in bytes rather than characters and keep their "(Year)". There's a new "Windows-safe file names" switch, off on this server because the library already uses
?in names, and on by default for new installs. - Saves and moves run one at a time.
4. Rough edges
Channel home pages now use their Videos tab instead of nesting tab groups. Lookups can't hang forever. Uploads are serialized per file and expire when abandoned. Subtitles use cookies when the video needed them. Re-matching a saved episode renames its files, and short channel names no longer match unrelated shows. There's also a "can't reach server" banner, a low-disk warning, and a clear message when Docker's data folder isn't writable.
5. Process notes
- Test suite:
tests/, 34 tests, run withvenv/bin/python -m pytest. They use a throwaway data folder with the Plex sync and self-update disabled; file moves run in temp folders. - Near miss: a preview instance built from a copy of the live DB re-queued Damien's in-progress download ("The Electric Company", 2.6 GB). That copy still points at the real
/medialibrary folders. I caught it within seconds, and only a partial file in scratch was written. Rule from now on: before starting any preview from a live-DB copy, set in-flight rows toerror. - Published:
skyhouse.dev/yt-plex/was rebuilt from the committed code (the source tarball is now agit archiveofHEAD), its checksums updated, and a fresh container verified.
Net effect: the one real crash is gone, the internet-facing surface is meaningfully harder, media files are safer to rename, and there's finally a test suite to refactor against.
← Back to Admin Hub