Skip to content

Security

Aerya edited this page Jul 15, 2026 · 1 revision

Security

  • Anti brute-force — The login endpoint blocks an IP after 5 failures within 5 minutes for 15 minutes. No external dependency: pure in-memory sliding window.
  • CSRF — All POST actions (forms and AJAX) are protected by a CSRF token via server-side session. The X-CSRF-Token header is automatically injected on every non-GET fetch request via a JavaScript interceptor.
  • XSS — Third-party API data (AirVPN) injected into the DOM via innerHTML is always escaped by a _esc() helper (HTML entity encoding) before insertion. Inline onclick/onchange attributes present in dynamic components only contain JSON-encoded values or constants — no raw user data is interpolated into them.
  • SECRET_KEY — The application refuses to start if SECRET_KEY is missing or equal to the default value. Generate a secure key with: openssl rand -hex 32.
  • Network exposure — Gunicorn listens on 0.0.0.0:8765. Do not expose this port directly to the internet. On a publicly accessible server, place Companion behind a reverse proxy (Nginx, Caddy, Traefik) with HTTPS and strong authentication, or restrict the binding to the local interface: 127.0.0.1:8765:8765 in your docker-compose.yml.
  • /metrics — Open by default on the LAN. If your machine is reachable from outside, set the METRICS_TOKEN environment variable or configure an API token in Settings → Maintenance → REST API: /metrics will use it automatically (Bearer token required in the Authorization header).
  • Sidecar — Each sidecar container (speed-test on port 8766, catalogue on port 8767) automatically receives a random secret generated by the Companion (SIDECAR_SECRET, 32 bytes of entropy via secrets.token_hex). Every HTTP request to the sidecar must include this secret in the X-Sidecar-Token header — a request without the correct token receives a 403. The secret is unique per instance and destroyed along with the container at the end of the test. These ports must not be reachable from untrusted networks: if your host is publicly accessible, restrict the port binding or isolate them with a firewall.
  • Secrets in /settings — The API token, proxy password, and webhook URLs are displayed in cleartext in the Settings page. Restrict access to Companion to trusted users only.
  • YAML/XML injection — The server filter value is sanitised before being written to docker-compose.override.yml in Compose mode (newlines stripped, quotes and backslashes escaped). In Unraid/DockerMan mode, values are escaped before being written to the XML template, with a timestamped .bak backup.
  • Docker socket — The Docker socket is secured via docker-socket-proxy, which restricts allowed calls to: read access (containers, images, networks, volumes) plus POST/DELETE for temporary sidecar management. Direct daemon access (exec, swarm, info…) is blocked.

Docker image security

Both images (gluetun-companion and gluetun-companion-sidecar) bundle third-party Go binaries (Docker CLI, Docker Compose, librespeed-cli, ookla speedtest) with their own dependency chains, invisible to Python package managers. A two-layer pipeline keeps these images up to date:

Dependabot (already in place, runs every Monday 06:00 UTC):

  • Updates pip dependencies for both Companion and Sidecar (automatic PRs; patch updates request auto-merge when that GitHub feature is enabled, minor updates remain under manual review)
  • Tracks Docker base images (python:3.12-slim) — Python runtime security rebuilds
  • Tracks GitHub Actions versions in CI workflows

Trivy workflow (.github/workflows/trivy-scan.yml, every Monday 07:00 UTC):

  • Builds both images and scans them with Trivy for HIGH and CRITICAL CVEs
  • Uploads results as SARIF to the repository's Security tab (Security → Code scanning)
  • If fixable CVEs are found and a newer Docker CLI image is available: automatically opens a PR bumping FROM docker:XX-cli in the Dockerfile
  • If no automatic fix is possible: opens an Issue listing the CVEs for manual review

Smoke test (.github/workflows/docker-publish.yml, on every PR):

  • Builds both images for amd64
  • Starts each container with a minimal configuration and checks it responds over HTTP within 20 seconds
  • Fails if an image no longer starts; it blocks merging when configured as a required check in the main branch protection rules

Gluetun Companion

Français

English


🇫🇷 Français · 🇬🇧 English

Clone this wiki locally