Why migrate now: CVE-2026-45618 and end of maintenance for the 1.x branch
CVE-2026-45618 is a critical vulnerability scored CVSS 10.0 in LiquidJS, the template engine used by Uptime Kuma for notification templates. LiquidJS versions prior to 10.26.0 are affected: by exploiting the valueOf filter in a template — in Uptime Kuma, the message template of a notification — an attacker can chain prototype manipulation to reach JavaScript's Function constructor and execute arbitrary commands on the host. A public proof-of-concept demonstrates file reads and execution via child_process.execSync.
The 1.x branch received no fix: its last release, 1.23.17 (October 2025), bundles LiquidJS 10.22.0, and the project now marks the 1 and latest Docker tags as deprecated. Editing a notification template requires an account: an attacker who obtains admin access — through stolen credentials or bruteforce — has this surface. The 2.x branch has shipped LiquidJS 10.26.0 since version 2.4.0 (May 2026) and keeps receiving fixes: 2.5.8, for example, fixed an authenticated code execution via Apprise (GHSA-v2p3-6f5h-6hhf) that also affects the whole 1.x branch. The latest release, 2.5.9, came out in October 2026. Running a 1.x instance means exposing every monitor — and the clients it watches — to an attack surface with no known closure date.
Concrete impacts of an unmigrated instance
- Remote code execution: an attacker who can edit a notification template can run system commands on the host VPS.
- Client portfolio exposure: an agency hosting a shared instance exposes the configurations, internal URLs, and notification credentials of all its clients.
- Transferred liability: in the event of an incident on an unmaintained instance, failure to migrate after a critical CVE is published constitutes an aggravating factor.
- CVE accumulation: the 1.x branch receives neither security patches nor dependency updates — every new flaw in LiquidJS or its dependencies accumulates without remedy.
- Silent detection: LiquidJS evaluates templates server-side; exploitation may remain invisible in Uptime Kuma application logs.
Prerequisites before you start
Check the following points before starting the migration. Missing one can make rollback impossible.
Minimum recommended resources. The Uptime Kuma documentation sets no figure: a small instance fits on an entry-level VPS, but RAM and disk grow with the number of monitors and the history kept. The migration aggregates the heartbeat table: the maintainer reports about 7 minutes for 20 monitors and 90 days of data, and hours on slow hardware — a VPS with NVMe SSD reduces this window.
Docker Compose v2. The required command is docker compose (integrated plugin), not docker-compose (standalone v1 binary). Check with docker compose version: expect version 2 or later (the current branch is v5). If the command fails, install the plugin via your distribution's package manager before continuing.
Root or sudo access. The procedure manipulates Docker volumes and system files; privileged access is mandatory.
Operational v1 instance. Confirm the current version via the web interface (Settings → About). The migration assumes the instance starts and that its database is consistent — if it is already corrupted, restore a backup first.
Mandatory backup before migration
The v1 → v2 migration transforms the SQLite schema irreversibly. Without a valid backup, a full rollback is impossible.
Identify the volume or data folder. If you use Docker Compose with a named volume, its full name combines the Compose project name and the volume name, for example uptime-kuma_uptime-kuma-data. Confirm with docker volume ls | grep kuma. If you use a bind mount, locate the path in your docker-compose.yml — typically ./data:/app/data.
Stop the container before the backup. A SQLite database backed up during active writes may be corrupted. Never use the -v flag when stopping: it would delete the volume and its contents.
Backing up the data volume
Stop Uptime Kuma
Stop the container without removing the volume:
docker compose downWait for the confirmation
Container uptime-kuma Stoppedbefore continuing.Back up a named Docker volume
Use a busybox container to create a compressed archive of the volume:
docker run --rm \ --volume uptime-kuma_uptime-kuma-data:/app/data \ --volume $(pwd):/backup \ busybox \ tar czf /backup/uptime-kuma-v1-backup.tar.gz -C /app/data .Check the archive size with
ls -lh uptime-kuma-v1-backup.tar.gz. An archive of only a few bytes indicates a mounting problem — fix it before continuing.Back up a bind mount
If your data is in a host folder (example:
./data):tar czf uptime-kuma-v1-backup.tar.gz ./dataKeep this archive off the server (object storage, remote server) before proceeding to the migration.
v1 → v2 migration: step-by-step procedure
Update the image in docker-compose.yml
Open your
docker-compose.ymland replace the image tag:# Before image: louislam/uptime-kuma:1 # After image: louislam/uptime-kuma:2If you use the
latesttag, prefer an explicit version tag likelouislam/uptime-kuma:2.5.9(latest release, October 2026) to avoid regressions during future automatic upgrades, and follow the repository's security advisories to move it forward. Avoidrootlesstags for this migration: the official guide advises against them when coming from v1.Pull the new image
Download the v2 image before starting the service:
docker pull louislam/uptime-kuma:2Verify the image is present:
docker images | grep uptime-kuma.Start the v2 container
Launch the service. Docker Compose detects the image change and recreates the container:
docker compose up -dWait for the confirmation
Container uptime-kuma Started.Follow the database migration
On first start, Uptime Kuma migrates the SQLite schema to the v2 format. This can take from a few seconds to several hours depending on database size and hardware speed:
docker compose logs -f uptime-kumaDo not interrupt the container during this phase. Wait for a line confirming the end of the migration before continuing.
Check the healthcheck
Verify the container is in
healthystate:docker compose psThe
Statuscolumn must showhealthy. If it stays onstartingfor more than two minutes after migration logs end, check the logs to identify the error.Confirm the active version in the interface
Log in to the web interface. Go to Settings → About and verify the displayed version starts with
2.. Confirm all your monitors are present and their statuses match the actual state of your services.
Post-migration checks
A successful migration is not just a container that starts. Go through these points before considering the operation complete.
Monitors. Open the dashboard and compare the monitor count with your v1 inventory. A missing monitor may indicate a partial migration issue — check logs at the ERROR or WARN level.
Notifications. Manually trigger a notification test for each configured channel (email, Telegram, webhook). In v2, email (SMTP) templates move from a regular-expression replacement to LiquidJS: variables become case-sensitive and an unknown variable is silently ignored. Use this opportunity to audit each notification template and remove any unexpected content ({% %} tags, valueOf filter) — this is the vector of CVE-2026-45618.
Status page. If you expose a public status page, verify it responds correctly and lists the right services. The URL and slug are preserved after migration.
SSL certificates. TLS probes restart their verification cycle after migration. A certificate close to expiry before the migration may trigger an alert immediately: verify the actual date before treating this as a regression.
Hardening the instance after migration
Mandatory authentication. In v2, authentication is enabled by default. Check in Settings → Security that passwordless access is disabled. On a freshly deployed instance with no account configured, the interface is publicly accessible during initial setup: create the admin account within the first minutes after the first start.
Dedicated subdomain behind a reverse proxy. Do not expose Uptime Kuma on a direct port (:3001). Place it behind Nginx or Caddy on a dedicated subdomain (status.your-domain.com) with TLS. A ufw deny 3001 is not enough: ports published by Docker bypass ufw rules. Publish the port on the loopback only in docker-compose.yml ("127.0.0.1:3001:3001") so that only the reverse proxy can reach it.
Fail2ban or CrowdSec in front of the proxy. Add a bruteforce detection rule on interface login attempts. The CrowdSec Hub offers a community collection, timokoessler/uptime-kuma, with a bruteforce scenario. See the article Securing your VPS with CrowdSec for the full procedure.
Network isolation. Place Uptime Kuma in a dedicated Docker network. It only needs to reach the targets it monitors — not your production databases or internal APIs.
Troubleshooting: common errors
Incompatible volume or corrupted database. If logs show SQLITE_ERROR: no such table or database disk image is malformed, the mounted database is not a valid Uptime Kuma v1 database, or the backup was taken while the database was being written. Restore the archive, stop the container cleanly, and restart the procedure from the backup step.
Port 3001 already in use. A port is already allocated or address already in use error on port 3001 means a process already uses this port. Identify it with ss -tlnp | grep 3001 and stop it, or change the port mapping in docker-compose.yml (for example 127.0.0.1:3002:3001) and update your reverse proxy configuration.
Notification template rejected after migration. If a notification channel shows a template error, the template contains syntax that LiquidJS refuses; in v1, SMTP email did not use LiquidJS but a simple regular-expression replacement. Edit the template in Settings → Notifications and remove or fix the offending tags.
TLS certificate shown as expired. TLS probes restart their cycle after migration. Verify the actual date with echo | openssl s_client -connect your-domain.com:443 -servername your-domain.com 2>/dev/null | openssl x509 -noout -dates before treating this alert as an incident.
Container in a restart loop. If migration fails and the policy is restart: always or unless-stopped, Docker will restart the container indefinitely. Switch to restart: "no" (quoted in YAML), fix the issue identified in the logs, then restore the original policy.
What this migration protects
Migrating to Uptime Kuma 2.x closes CVE-2026-45618 on a surface directly accessible from the administration interface. For an agency managing multiple clients' infrastructure from a shared instance, this surface is proportional to the number of accounts and monitors configured: each additional client widened the exposed perimeter.
v2 also brings structural changes that reduce the long-term attack surface: rootless Docker images offered as an option (2-rootless tags), actively maintained dependencies, and a 14-day delay before integrating new npm dependency versions (min-release-age=14 in the project's .npmrc) — to limit supply chain attacks.
With a ServOrbit.com Agency plan, you create and track your clients' cPanel accounts from one space.