v1.3.3 — Security hardening
Security hardening release
Comprehensive audit + fix pass: 4 Critical, 10 High, 6 Medium issues resolved. See README changelog for full details.
Critical
- Trust cookie now signs
deviceIdand expiry into the payload — stolen cookies can no longer be replayed with an attacker-chosenX-Emby-Device-Id. Cookie rotates on every use. - Token-approval race between SessionStarted and middleware bound to
(userId, deviceId, token)and single-consume. - Recovery codes upgraded to PBKDF2-SHA256 (legacy codes still validate during transition).
- Open redirect via
/TwoFactorAuth/Challenge?return=closed (same-origin enforcement).
High
- Case-sensitive deviceId comparisons (homograph bypass closed)
- Pairing approve refuses
Guid.Empty/ empty deviceId RegisteredDeviceIdscapped + validatedIsAuthPathanchored — no more confused-deputy- Anti-clickjacking headers on all embedded pages
- Rate limiter proxy-aware (
X-Forwarded-Forwhen behind trusted proxy), IPv6/64bucketed - Per-user rate limit on
/Verifyin addition to per-IP /Pairings/Initiateinput sanitized
Medium
- inject.js redirects to a hardcoded path
TestSmtpno longer leaksex.Message- Device revoke wipes in-memory bypass flags and logs out access tokens
- PairConfirm replay protection
- API keys hashed at rest (auto-migration from legacy plaintext)
- CookieSigner timing oracle removed
Other
- Settings tile renders inline with sibling tiles under themed drawers
- Diagnostic logs moved to Debug
- LAN bypass auto-registers deviceId and clears stale pending entries
Install
Add the manifest to your Jellyfin: https://raw.githubusercontent.com/ZL154/JellyfinSecurity/main/manifest.json