Forgejo shipped emergency releases 16.0.4 and 15.0.8 on September 10 to fix CVE-2026-89094, a CVSS 9.9 remote code execution flaw in the “generate repository from template” feature. Gitea, the project Forgejo forked from, shares the vulnerable code path and patched its own variant (CVE-2026-25718) in 1.25.5 the same week. Any authenticated user with permission to create a repository from a template — the default for ordinary accounts on most instances — can use it to run arbitrary commands as the forge’s service account.
What happened
Generating a repository from a template in Forgejo/Gitea runs through four steps: clone the template repository, delete its .git directory, expand template variables in any files listed under .forgejo/template, then run git init to turn the result into a fresh repository. The bug lives in the gap between steps three and four.
Template variable expansion writes attacker-controlled content to arbitrary paths inside the working directory before that directory is git-initialized. A malicious template can abuse this to recreate a .git folder — including a hooks/ subdirectory holding executable scripts — during expansion. When git init runs immediately afterward, Git detects the pre-existing .git directory and adopts it rather than creating a clean one, so the planted hooks survive. The very next Git operation Forgejo performs against that repository (which happens immediately, as part of the same request) triggers hook execution with the privileges of the Forgejo/Gitea OS user. One published proof-of-concept goes further, using the same primitive to write directly into ~/.ssh/authorized_keys for the service account, skipping hooks entirely and getting an interactive shell over SSH.
This is CWE-78 (OS command injection) layered on a CWE-22-style path handling failure: the template-expansion step never validated that it was only ever writing inside the intended working tree, and never checked that no .git directory existed before handing off to git init.
Impact
The privilege bar is low by design — creating a repository from a template is a normal, unprivileged action on virtually every Forgejo/Gitea instance, including ones with self-registration enabled. That means the practical attacker profile is the same as recent Gitea diffpatch and registry bugs: anyone who can get an account, which on a lot of internet-facing instances means anyone at all.
Code execution as the Git-forge service account is a strong foothold. These processes typically hold the keys to everything downstream of the forge: SSH host and deploy keys, OAuth client secrets, webhook signing secrets, CI/CD runner tokens, and often direct network reach into build infrastructure. A forge compromised this way is a supply-chain pivot point, not just a defaced wiki — an attacker can tamper with any repository the service account can write to, poison CI configuration, or plant backdoors in released artifacts.
Affected versions
- Forgejo: 16.0.3 and earlier on the stable branch, 15.0.7 and earlier on LTS. Fixed in 16.0.4 and 15.0.8 (September 10, 2026).
- Gitea: 1.25.4 and earlier carry the same template-expansion flaw. Fixed in 1.25.5, tracked as CVE-2026-25718.
No public evidence of in-the-wild exploitation has surfaced yet, but proof-of-concept code is already public, and the technique is trivial to weaponize once you know the four-step template flow.
Mitigation
- Upgrade now: Forgejo to 16.0.4/15.0.8, Gitea to 1.25.5 or later. This is the only real fix — the vulnerable window between variable expansion and
git inithas no safe workaround short of patched code. - Restrict “create from template” to trusted users/organizations if you can’t patch immediately; the feature, not repository creation in general, is the trigger.
- Audit template repositories on your instance for suspicious
.forgejo/templateentries, and check service-accountauthorized_keysand any repohooks/directories for unrecognized entries if you suspect prior abuse. - Rotate forge-held secrets (SSH deploy keys, OAuth secrets, webhook tokens, CI credentials) if you find evidence of exploitation before patching.
- Limit internet exposure of self-hosted instances that don’t need to be public-facing; this bug only requires an authenticated low-privilege account, so anything that widens who can get one widens the blast radius.