Skip to content

Release v2.22.0 — security hardening - #211

Merged
s0len merged 8 commits into
mainfrom
develop
Jul 8, 2026
Merged

Release v2.22.0 — security hardening#211
s0len merged 8 commits into
mainfrom
develop

Conversation

@s0len

@s0len s0len commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Promotes the v2.22.0 security-hardening work from develop to main for tagged release.

Highlights (full detail in CHANGELOG [2.22.0]):

  • Opt-in GUI authentication (GUI_PASSWORD), randomized session secret, secret masking in editors.
  • Kometa docker_binary allowlist; local-asset slug sanitization; SMTP TLS verification; webhook-URL log redaction; http(s)-only artwork relay.
  • GUI default bind → 127.0.0.1 (Docker keeps 0.0.0.0); non-root container; removed unused browser-use; NICEGUI_STORAGE_PATH defaulted in entrypoint.

Verified: 1497 tests, lint/format, all CI green; deployed to prod (develop channel) and GUI login confirmed working.

🤖 Generated with Claude Code

s0len and others added 8 commits July 8, 2026 20:31
Security hardening for the web GUI (previously unauthenticated and bound to
all interfaces):

- Add opt-in login (new gui/auth.py): a Starlette middleware redirects
  unauthenticated browsers to /login and 401s /api/* requests. Enabled only
  when GUI_PASSWORD is set; a loud warning is logged when it is not.
  Credentials come from env vars (GUI_USERNAME/GUI_PASSWORD) and are compared
  in constant time over UTF-8 bytes.
- Default bind host is now 127.0.0.1 (the Docker image keeps GUI_HOST=0.0.0.0
  for container/Service access).
- Replace the hardcoded storage_secret with GUI_STORAGE_SECRET or a random
  per-process value, so session cookies can't be forged with a published key.
- Mask password fields in the settings editors: stored secrets are never sent
  to the browser, and a blank password field on save keeps the existing value
  (see secret_display_value / apply_field_change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- kometa_trigger: restrict docker_binary to known container runtimes
  (docker/podman/nerdctl by filename) at config load and again as a runtime
  guard before Popen, blocking a swap to /bin/sh + args (arbitrary execution).
- local_assets: sanitize the API-supplied show slug into a single path
  component and add a resolved-path containment check, so a malicious slug
  can't read files outside the fallback assets directory.
- notifications/email: pass a verifying ssl context to SMTP starttls
  (smtplib does not verify certificates by default), preventing credential
  capture by an on-path attacker.
- notifications: add redact_url() and use it for Discord/Slack/webhook failure
  logs so capability-URL tokens no longer leak into logs; log exception class
  names instead of full messages.
- plex_metadata_sync: only relay http(s) artwork URLs to Plex, rejecting
  file:// and other schemes a compromised metadata source could supply.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Dockerfile: add a non-root user (uid 1000) and run as it. Requires the
  runtime volumes (/config, /data) to be writable by that uid — in Kubernetes
  set securityContext.fsGroup=1000 (with fsGroupChangePolicy: OnRootMismatch).
- Remove the browser-use dependency: it was declared in pyproject but never
  imported anywhere, and was absent from requirements.lock, so editable installs
  pulled in a large unused tree (Playwright, LLM SDKs) for no benefit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Security hardening: GUI auth, path traversal, subprocess & notification fixes
Fixes the failing `ruff format --check` CI lint step (format-only, no logic
change) in command_help.py and gui/auth.py.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Enabling GUI login uses app.storage.user, which NiceGUI persists to a file
store under a path resolved from NICEGUI_STORAGE_PATH at import time
(default ./.nicegui under /app). As the non-root container user that path is
not writable, so login sessions failed to persist. entrypoint.sh now defaults
NICEGUI_STORAGE_PATH to STATE_DIR/.nicegui (respecting an explicit override),
and app.py documents that the env var — not app.storage.path — controls it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(gui): point NiceGUI storage at writable state dir
Security-hardening release: opt-in GUI auth, path-traversal/subprocess/
notification fixes, non-root container. See CHANGELOG for details and
behavior changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gitguardian

gitguardian Bot commented Jul 8, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 4 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
34667823 Triggered Username Password 8e443af tests/test_gui_auth.py View secret
34667822 Triggered Generic Password 8e443af tests/test_gui_auth.py View secret
34667822 Triggered Generic Password 885f37c tests/test_gui_auth.py View secret
34667823 Triggered Username Password 885f37c tests/test_gui_auth.py View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secrets safely. Learn here the best practices.
  3. Revoke and rotate these secrets.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@s0len
s0len merged commit 28dec03 into main Jul 8, 2026
8 of 9 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.

1 participant