Forgejo RCE Vulnerability: Patch Your Homelab Server Now

Forgejo 16.0.4 and 15.0.8 fix a critical RCE through malicious template repositories. Who is exposed, how to update Docker and binary installs, and hardening.

Terminal window showing a Docker pull command updating a Forgejo container to patch the latest RCE vulnerability

Forgejo 16.0.4 and 15.0.8, released on 10 September 2026, fix a vulnerability the release notes rate critical: a malicious template repository could be used to read arbitrary data from the Forgejo host and execute arbitrary processes on it.

How it worked, per the release notes: when you create a repository from a template, Forgejo clones the template, removes its .git folder, expands template variables in the files listed in .forgejo/template, and then initialises a new git repository. The variable expansion could be abused to create a new .git folder, which git then adopted during initialisation. The fix removes any .git folder after expansion.

The same releases fix a second issue: API tokens restricted to certain repositories could modify branches outside their permission through the “allow maintainer edit” path on pull requests.

Who is exposed: any instance where someone who could create or import a malicious template repository is able to generate repositories from it: other users, open registration, or a compromised account. A single-user instance that never uses untrusted templates is at lower risk, but should update anyway.

Phase 1: Force a Manual Backup

Never pull a new Docker image or replace a binary without a backup. Database migrations fail. Data gets corrupted. You need a verified rollback path.

If you use SQLite, backing up is a simple file copy. Stop the Forgejo service first to prevent locked database writes.

sudo systemctl stop forgejo
# Or for Docker: docker compose stop forgejo
cp /var/lib/forgejo/data/forgejo.db /var/lib/forgejo/data/forgejo.db.bak_16.0.3

If you use PostgreSQL, do not copy the raw database files. You must create a SQL dump. Run this against your active Postgres container or local service:

docker exec -t forgejo-db pg_dump -U forgejo forgejo > /opt/backups/forgejo_pre_update.sql

Archive your custom configurations and repository data. The app.ini file dictates how your instance runs. If the update overwrites it, your server goes down.

tar -czvf /opt/backups/forgejo_data_pre_update.tar.gz /etc/forgejo /var/lib/forgejo

Phase 2: The Forgejo Update Docker Process

The fastest way to patch is via Docker. A standard forgejo update docker workflow involves pulling the specific release tag and recreating the container.

Do not use the :latest tag. Unpinned tags cause unexpected major version upgrades, breaking dependencies and database schemas without warning. Pin a specific version (at least 16.0.4, newer patch releases are better) or the 16 tag, which the Forgejo docs say tracks the latest 16.x release, if you trust minor updates.

Open your docker-compose.yml file and update the image tag:

services:
  server:
    image: codeberg.org/forgejo/forgejo:16.0.5
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - forgejo
    volumes:
      - /opt/forgejo/data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"
    security_opt:
      - no-new-privileges:true

  db:
    image: postgres:16-alpine
    restart: always
    environment:
      - POSTGRES_USER=forgejo
      - POSTGRES_PASSWORD=your_secure_password
      - POSTGRES_DB=forgejo
    networks:
      - forgejo
    volumes:
      - /opt/forgejo/postgres:/var/lib/postgresql/data

networks:
  forgejo:
    external: false

Pull the new image and recreate the stack. Docker replaces the running container with the patched version. The database remains intact on the mapped volume.

cd /opt/forgejo
docker compose pull
docker compose up -d

Check the logs immediately to confirm the database migration succeeded and the service is listening.

docker compose logs -f server

Look for the line indicating successful startup: Listen: http://0.0.0.0:3000. If you see a database schema mismatch error, restore your PostgreSQL dump and verify you did not skip a required major version upgrade.

Phase 3: Proxmox LXC Bare Metal Upgrade

If you installed Forgejo directly on a Debian or Ubuntu LXC container in Proxmox, you update by replacing the binary.

First, stop the running service.

sudo systemctl stop forgejo

Navigate to your installation directory and download the compiled binary (16.0.5 at the time of writing) from the official release repository. Verify your architecture. Most homelabs use amd64, but Raspberry Pi clusters require arm64.

cd /usr/local/bin
sudo wget -O forgejo-16.0.5 https://codeberg.org/forgejo/forgejo/releases/download/v16.0.5/forgejo-16.0.5-linux-amd64

Set the executable bit and replace the old symlink.

sudo chmod +x forgejo-16.0.5
sudo ln -sf forgejo-16.0.5 forgejo

Restart the systemd service.

sudo systemctl start forgejo
sudo systemctl status forgejo

Phase 4: Self-Hosted Git Security Homelab Hardening

Applying the patch fixes the immediate threat. You must still address the configuration flaws that made the exploit dangerous. Standard self-hosted git security homelab practices mitigate the blast radius of future vulnerabilities.

Disable Open Registration

Most homelab users host repositories for themselves or a small group of known collaborators. Open registration provides attackers a free authenticated account, bypassing unauthenticated exploit checks.

Edit your /etc/forgejo/app.ini (or the mapped Docker equivalent at /data/gitea/conf/app.ini):

[service]
DISABLE_REGISTRATION = true
REQUIRE_SIGNIN_VIEW = true

Setting REQUIRE_SIGNIN_VIEW blocks unauthenticated users from browsing public repositories. This prevents information disclosure and thwarts automated scanners indexing your source code.

Implement Fail2Ban

Git servers face constant brute-force SSH and HTTP login attempts. Forgejo outputs structured logs for failed authentication. Map a fail2ban instance to read the Forgejo log directory and block offending IPs at the firewall level.

Create a specific filter for Forgejo in /etc/fail2ban/filter.d/forgejo.conf:

[Definition]
failregex =  .*Failed authentication attempt for .* from <HOST>
             .*Failed login for .* from <HOST>
ignoreregex =

Consider the rootless image

The standard Forgejo image starts as root and then drops to the git user, so it needs the capabilities for switching users: dropping all capabilities on it breaks startup. If you want the container to never run as root, use the rootless image documented by Forgejo: codeberg.org/forgejo/forgejo:16-rootless with user: 1000:1000, data under /var/lib/gitea and SSH on port 2222 inside the container. See the Forgejo Docker docs.

Restrict who can use templates

The vulnerability needed a malicious template repository. On a small instance, that’s another reason to disable open registration (above) and only trust templates from people you know.

Audit the Actions Runner

If you use Forgejo Actions, audit your runner configuration. The runner executes untrusted code by design. Never run the Forgejo runner binary directly on the host machine. Always use the Docker-in-Docker or isolated container approach. If an RCE breaks out of the runner environment, it should hit an isolated container boundary, not your hypervisor kernel.

Check your instance logs for signs of compromise prior to patching. Look for anomalous processes executing under the git user, unexpected outgoing network connections to unknown IP addresses, or newly created administrator accounts. If you suspect an intrusion, nuking the container and restoring from an older offline backup is the only safe remediation.

What’s Next

Frequently Asked Questions

What exactly does the Forgejo 16.0.4 fix?
The release notes rate it critical: when a new repository was generated from a template, template variable expansion could be abused to create a .git folder that git then adopted. A malicious template repository could read data from the Forgejo host and run processes on it.
Which versions should I run?
16.0.4 or later on the 16 branch, or 15.0.8 or later on the 15 branch. At the time of writing, 16.0.5 and 15.0.9 are the newest releases, so update to those.
Does it affect Gitea too?
The Forgejo release notes don't say. Forgejo is a hard fork with its own code, so check Gitea's own security announcements rather than assuming.

Get notified when new articles and designs land:

No spam. Unsubscribe any time.

Sergej Voronko
Sergej Voronko
SAP Basis · Senior Operations Manager · Linux infrastructure engineer
About the author →

[discussion]

Comments are powered by Giscus — backed by GitHub Discussions. Sign in with GitHub to join the conversation.