Skip to content

v1.9.7

Choose a tag to compare

@github-actions github-actions released this 21 May 15:52
· 50 commits to main since this release

v1.9.7

Security-only release. No new features, no UI changes, no data migration. Built on the v1.9.6 plugin behavior; install in place.

Security fixes

This release closes findings from a code-level security review (see SECURITY_REVIEW.md) plus the issues CodeQL's first run on the repo flagged.

Higher-severity fixes

  • Per-user attachment storage quota (was unbounded). An authenticated user could spam chat attachment uploads — each within the existing 8 MB per-file cap — until your disk filled. Now bounded at 200 files / 200 MB total per user. Existing attachments are unaffected; the next upload that would cross the cap returns a clean error message asking the user to delete old files first. (Services/MessagingService.cs)
  • Anonymous profile-card CSP tightened. script-src 'unsafe-inline' removed from the public profile-card endpoint's Content-Security-Policy. The template never used inline scripts, so the allowance was pure defense-in-depth weakening. style-src 'unsafe-inline' is still present (the embedded <style> block uses per-render template variables and migrating to a nonce-based allowlist is a follow-up). (Api/AchievementBadgesController.cs)

Defense-in-depth + correctness

  • SVG sanitizer extended: <animate> and <set> SMIL animation elements now blocked alongside <script>/<foreignObject>/<iframe>/<embed>/<object>. SMIL animation can mutate an attribute at render time (e.g., animate href to a javascript: URI on SVG-capable clients) past the static post-parse scan.
  • Webhook URL DNS resolution bounded at 3s. Previously Dns.GetHostAddresses was synchronous with no caller-side timeout — a slow resolver could stall an admin request for the OS DNS-client default (5-30 s). Times out cleanly now and fails-closed.
  • Audit-log endpoint ?limit= clamped at the controller layer to [1, 1000]. Service-level cap (5000 max entries) is unchanged; this just stops int.MaxValue from forcing the larger O(N) response.

Resource cleanup

  • MessagingService and AchievementBadgeService now implement IDisposable. Both classes own a Timer (the debounced-save throttle). Without IDisposable, the Timer's delegate kept the singleton rooted across plugin reloads — a slow leak. Now released cleanly on plugin unload.

CI / CodeQL / Scorecard

  • CodeQL first scan baselined. 100+ alerts triaged: real findings fixed above; the rest are ASP.NET structured-logging false positives (cs/log-forging), graceful-degradation patterns (cs/empty-catch-block, cs/catch-of-all-exceptions), and style-only hints already covered by NetAnalyzers. Suppression list with per-rule justifications in .github/codeql/codeql-config.yml.
  • Scorecard Pinned-Dependencies fix: the existing security.yml workflow now SHA-pins actions/checkout, actions/setup-dotnet, and gitleaks/gitleaks-action instead of using floating tags. Brings the workflow in line with the rest of the CI fleet (ci.yml / codeql.yml / scorecard.yml / release.yml were already SHA-pinned).

Deferred (acknowledged, not in this release)

  • style-src 'unsafe-inline' on the anonymous profile-card endpoint (requires nonce migration of the templated <style> block).
  • Audit-log details field still uses string concatenation with raw usernames. JSON serialization at file-level escapes correctly, so the risk is parsing ambiguity not log injection. Will swap to a structured Details object in a follow-up.
  • FriendsSimpleMode admin toggle enumerates all server users — documented behavior, no code change planned.

Upgrade

Drop-in replacement. No config changes, no data migration. Existing chat attachments are unaffected by the new quota (only new uploads are checked).

Package checksums

  • MD5: see Jellyfin.Plugin.AchievementBadges_1.9.7.0.md5
  • SHA256: see Jellyfin.Plugin.AchievementBadges_1.9.7.0.sha256

Sigstore-signed + SLSA build-provenance attested. Verify with cosign verify-blob or gh attestation verify.