Skip to content

Security

60plus edited this page Jul 11, 2026 · 2 revisions

Security

GamesDownloader ships with a layered set of defensive controls covering authentication, network access, server-side fetching, and stored secrets. This page is the map: it explains the design stance behind the hardening and gives a one-line summary of each control with a link to where it is configured or explained in depth. For the step-by-step how-to, see Network & Security.

Contents

Design stance and threat model

GamesDownloader is a self-hosted application. The design deliberately accepts two facts:

  • LAN-only with no reverse proxy must keep working. A plain docker compose up reachable only on your local network is a fully supported deployment. None of the built-in controls require a TLS-terminating proxy, HSTS, or a public hostname to run. Features that only make sense with HTTPS (such as Strict-Transport-Security) activate themselves automatically when a proxy signals a secure connection and stay dormant otherwise.
  • Securing the local network is the administrator's responsibility. The application does not try to defend against an already-hostile LAN. If untrusted devices share your network, isolate the app port at the firewall or bind it to your reverse proxy host.

The priority of the built-in controls is narrow and explicit: prevent compromise when you choose to expose the instance to the internet. That means preventing remote code execution, account takeover, and the server being tricked into reaching internal services. Everything below is oriented around those three outcomes.

Two things are out of scope by design. Plugins run trusted server-side code (installing a plugin is equivalent to trusting its author with your server), so plugin isolation is handled by gating and documentation rather than a sandbox - see Plugin Trust Model. And a compromised or hostile LAN is assumed to be the operator's problem, not the app's.

Authentication

  • JWT access + refresh tokens. Short-lived access tokens carry the user, role, and permission scopes; longer-lived refresh tokens mint new access tokens. Every token carries a random 128-bit jti, so individual sessions can be revoked instantly via a Redis blocklist with a database session check as a fallback. Configured under Users & Permissions.
  • bcrypt password hashing. Passwords are hashed with bcrypt (per-password salt); plaintext is never stored.
  • Optional TOTP two-factor. Standard RFC 6238 authenticator-app codes (Google Authenticator, Authy, 1Password, and similar). A candidate secret is held in a short-lived pending buffer and only persisted once the user proves they configured their app; one-time recovery codes are themselves stored as bcrypt hashes so a database leak yields no working backup keys.
  • Single Sign-On (SSO). OpenID Connect providers plus Google, GitHub, and Microsoft, in alongside or replace login modes. See Users & Permissions.

Network and abuse protection

  • Brute-force protection. Redis fixed-window rate limiting per client IP with configurable attempt threshold, ban duration, and whitelist. The configurable ban guards the login endpoint and the Basic-auth path, so credential guessing on API requests cannot slip past it. Registration and token refresh are protected separately by a fixed HTTP 429 rate limit that issues no ban and shares no counter with login.
  • Safe real-IP handling. Forwarded headers (CF-Connecting-IP, X-Real-IP, X-Forwarded-For) are honoured only when the direct TCP peer is a trusted proxy - either a private/LAN address or one you list explicitly. A client connecting directly from an untrusted peer cannot spoof its address to dodge the IP allowlist or a ban.
  • IP allowlist and trusted-proxy / CORS control. Optionally restrict access to specific IPs or CIDR ranges, declare which upstream proxies to trust, and set allowed CORS origins - all applied dynamically without a restart.

All of the above are configured in Network & Security.

Server-side fetching and injection

  • SSRF guards on server-side URL fetching. Before the server fetches a user-supplied URL, its host is resolved and checked: loopback, link-local (including the 169.254.169.254 cloud-metadata endpoint), reserved, unspecified, and multicast addresses are always rejected. Private LAN addresses are rejected too, except on the URL-upload endpoint where a self-hoster may legitimately pull a file from their own NAS. This stops a crafted URL from reaching internal admin ports or metadata services.
  • Sanitised HTML on user-supplied content. Fields that render rich text (game descriptions, usernames, notification bodies, and similar) are passed through an HTML sanitiser on the client, and the Content-Security-Policy blocks inline script execution as a second line of defence, so an injected <script> in scraped or user-entered text cannot run.

Secrets and configuration hardening

  • Strong auth secret enforced at startup. The app refuses to start if GD_AUTH_SECRET_KEY is a known default or empty value (signing with a public value is a total auth bypass), and treats a secret shorter than 32 characters as fatal in production. See Configuration.
  • Secrets encrypted at rest. Sensitive configuration values - scraper API keys, the SMTP password, and OAuth client secrets - are encrypted with a key derived from the auth secret before they are written to the database, so a database dump alone does not expose them.

Access control and distribution

  • Role-based access control. Four roles (Admin, Uploader, Editor, User) map to permission scopes, with per-user grant/revoke overrides and per-game access restrictions layered on top. See Users & Permissions.
  • Download tokens. Shareable, time-limited download links that can be capped by a maximum download count and optionally protected with a password, letting you hand out a single file without granting an account. See Downloads & Torrents.

Content scanning, headers, and monitoring

  • ClamAV antivirus. Bundled in the container for manual and automatic scans (on upload and after GOG downloads), with live progress and scan history. First run: Settings → Security → ClamAV, then Update Definitions.
  • Security headers. X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and X-XSS-Protection on every response, a restrictive Content-Security-Policy that locks script execution to the app's own origin, and Strict-Transport-Security added only when the connection is HTTPS.
  • Audit log. A rolling, filterable log of security events (logins, IP unbans, password resets, and TOTP changes) in the admin UI. A brute-force ban itself is not an audit event - it is recorded in the application log and can raise an email alert.
  • Email security alerts. Optional per-event notifications for failed logins, logins from new IP addresses, new registrations, admin privilege grants, and brute-force bans, plus a periodic security report. See Email & Notifications.

Control summary

Control Prevents Where
JWT + bcrypt + TOTP Account takeover Users & Permissions
Session revocation (jti blocklist) Stolen-token reuse Users & Permissions
Brute-force + safe real-IP Credential guessing, ban evasion Network & Security
IP allowlist / trusted-proxy / CORS Unwanted network access Network & Security
SSRF guard Reaching internal services Network & Security
HTML sanitising + CSP Script injection (XSS) this page
Startup auth-secret check Token forgery Configuration
Encrypted secrets at rest Database-dump exposure Configuration
RBAC + per-game access Privilege escalation Users & Permissions
Download tokens Uncontrolled file sharing Downloads & Torrents
ClamAV Malware distribution Configuration
Security headers Clickjacking, MIME sniffing this page
Audit log + email alerts Undetected intrusion Email & Notifications

The + in the following capability view marks where each protection applies:

Deployment Auth + RBAC Brute-force Security headers HSTS Encrypted secrets
LAN-only, no proxy + + + +
Behind HTTPS reverse proxy + + + + +

Note: plugins are trusted server-side code and are intentionally excluded from this hardening model. Only install plugins you trust, and read Plugin Trust Model before exposing an instance that accepts plugin uploads.

Next: Network & Security for the configuration how-to, and Plugin Trust Model for the plugin threat model.

Clone this wiki locally