> PR: Critical: fix: prevent template expansion from interfering with git repo initialization. When generating a new repository from a template repository, Forgejo clones the template repository, removes the .git folder, performs variable template expansion on files listed in .forgejo/template, and initializes a new git repository. During this process, variable template expansion could be misused in order to create a new .git folder, which git would adopt and incorporate during its initialization of a new git repository. A malicious template repository could be used to read arbitrary data from the Forgejo host, and to execute arbitrary processes on the Forgejo host, as a remote code execution attack. To address this issue, after variable expansion is completed, any existing .git folder is removed from the directory before the git repository is initialized.
show comments
techknowlogick
Only posting here because I've been asked about it. Gitea is protected against both of these issues.
(bias note: part of project leadership of Gitea)
Edit: As a note, security incidents happen to everyone and we shouldn't shame anyone for reporting them, especially as that'd otherwise cause less issues to be reported overall.
show comments
keel-control
This was my first thought after they disallowed LLM contributions.
They may not use AI to check for vulnerabilities but attackers are going to which puts themselves at the disadvantage.
show comments
Macha
Since the release notes is currently unreadable due to codeberg rate limits, the two fixes in the release notes are:
*Critical:* fix: prevent template expansion from interfering with git repo initialization. When generating a new repository from a template repository, Forgejo clones the template repository, removes the `.git` folder, performs variable template expansion on files listed in `.forgejo/template`, and initializes a new git repository. During this process, variable template expansion could be misused in order to create a new `.git` folder, which git would adopt and incorporate during its initialization of a new git repository. A malicious template repository could be used to read arbitrary data from the Forgejo host, and to execute arbitrary processes on the Forgejo host, as a remote code execution attack. To address this issue, after variable expansion is completed, any existing `.git` folder is removed from the directory before the git repository is initialized.
ensure authorization reducer is accessed when checking editable PRs in APIs. When editing a git repo contents through Forgejo's API, a specialized security control is used to permit repository maintainers to edit branches that they do not own when an open pull request with the "allow maintainer edit" option is present. This specialized security control did not take into account API-specific security restrictions, such as repo-specific access tokens. As a result, it was possible for an API access token with restricted permission to make modifications outside of that restricted permission. The specialized security control has been updated to take into account API authentication security restrictions.
---
So if like me you run a private forgejo instance with closed signups and limited repository creation, you can wait for the update. Otherwise maybe take it off the public internet for a bit?
nirui
I'm just reading the code here:
// Before template expansion, .git was removed so that a fresh repo can be initialized; remove it again in case
// some template variable usage has conflicted with this directory and impacts git operations.
if err := root.RemoveAll(".git"); err != nil {
return fmt.Errorf("unable to remove .git folder")
}
Why the `err` isn't carried by the error message? For security? Then maybe log it internally?
User/operator can't really fix the problem if you keep giving them information this vague.
jzebedee
Relevant change:
Security bug fixes
PR: Critical: fix: prevent template expansion from interfering with git repo initialization. When generating a new repository from a template repository, Forgejo clones the template repository, removes the .git folder, performs variable template expansion on files listed in .forgejo/template, and initializes a new git repository. During this process, variable template expansion could be misused in order to create a new .git folder, which git would adopt and incorporate during its initialization of a new git repository. A malicious template repository could be used to read arbitrary data from the Forgejo host, and to execute arbitrary processes on the Forgejo host, as a remote code execution attack. To address this issue, after variable expansion is completed, any existing .git folder is removed from the directory before the git repository is initialized.
show comments
rcleveng
```
This git endpoint is seeing a high influx of requests for this repository, to preserve the availability of Codeberg your search request will not be processed. Sorry for the inconvenience and please try again later.
```
Any mirror?
show comments
mmsc
Wonder how long it took from report to patch. IME codeberg has one of the rudest security teams in oss (fair enough or not, irrelevant). https://news.ycombinator.com/item?id=47941590 Is quite relevant
show comments
tugback
Removing .git after expansion seems fragile. Sandboxing the git step would close the whole class of bugs.
miguelgrinberg
For those on version 15 LTS, this fix was released with v15.0.8.
show comments
n3mes1s
I'm working on a tool to reproduce stuff like this exactly.
Yep this is an RCE with the forgejo user on the host.
This is why I prefer simpler setups for personal use/hosting. Something like cgit that has no accounts has much less surface area for this kind of issue.
nightpool
What does the error message mean by "Your search request"? Why is viewing a single file in a repository considered a search request? That smells like poor caching somewhere
Sphax
Can't load the page but hopefully it's on an endpoint sitting behind my Tinyauth protection.
teaearlgraycold
Glad I have my Forgejo service set to auto update.
dboreham
Quick note that this is not an RCE in the typical sense that I can rock up to a Forgejo installation and execute code on the server. The attack vector here is via a template repo specified when initializing a new repo. The template repo could contain malicious code that then executes on the host server. So if you don't create new repos from mystery meat template repos, you should be ok.
show comments
bakugo
Trying to open any codeberg.org page from my main Helium browser results in a 403 just saying "Bye". Opening in Chrome or Firefox works fine. Very confusing.
rvz
As I said before for patching vulnerabilities in the age of AI [0], attackers are going to build exploits around this RCE with AI or even find more flaws with AI.
This means you have no choice but to use AI to defend, find and patch these flaws before attackers quickly build and use these exploits to target users.
You cannot afford to disallow or have a 100% ban on LLM contributions while attackers do not care and will use AI to find the flaws and attack you faster than you can triage it.
You should change the URL to https://codeberg.org/forgejo/forgejo/milestone/139655
> PR: Critical: fix: prevent template expansion from interfering with git repo initialization. When generating a new repository from a template repository, Forgejo clones the template repository, removes the .git folder, performs variable template expansion on files listed in .forgejo/template, and initializes a new git repository. During this process, variable template expansion could be misused in order to create a new .git folder, which git would adopt and incorporate during its initialization of a new git repository. A malicious template repository could be used to read arbitrary data from the Forgejo host, and to execute arbitrary processes on the Forgejo host, as a remote code execution attack. To address this issue, after variable expansion is completed, any existing .git folder is removed from the directory before the git repository is initialized.
Only posting here because I've been asked about it. Gitea is protected against both of these issues.
(bias note: part of project leadership of Gitea)
Edit: As a note, security incidents happen to everyone and we shouldn't shame anyone for reporting them, especially as that'd otherwise cause less issues to be reported overall.
This was my first thought after they disallowed LLM contributions.
They may not use AI to check for vulnerabilities but attackers are going to which puts themselves at the disadvantage.
Since the release notes is currently unreadable due to codeberg rate limits, the two fixes in the release notes are:
https://codeberg.org/forgejo/forgejo/pulls/14301:
*Critical:* fix: prevent template expansion from interfering with git repo initialization. When generating a new repository from a template repository, Forgejo clones the template repository, removes the `.git` folder, performs variable template expansion on files listed in `.forgejo/template`, and initializes a new git repository. During this process, variable template expansion could be misused in order to create a new `.git` folder, which git would adopt and incorporate during its initialization of a new git repository. A malicious template repository could be used to read arbitrary data from the Forgejo host, and to execute arbitrary processes on the Forgejo host, as a remote code execution attack. To address this issue, after variable expansion is completed, any existing `.git` folder is removed from the directory before the git repository is initialized.
https://codeberg.org/forgejo/forgejo/pulls/14301:
ensure authorization reducer is accessed when checking editable PRs in APIs. When editing a git repo contents through Forgejo's API, a specialized security control is used to permit repository maintainers to edit branches that they do not own when an open pull request with the "allow maintainer edit" option is present. This specialized security control did not take into account API-specific security restrictions, such as repo-specific access tokens. As a result, it was possible for an API access token with restricted permission to make modifications outside of that restricted permission. The specialized security control has been updated to take into account API authentication security restrictions.
---
So if like me you run a private forgejo instance with closed signups and limited repository creation, you can wait for the update. Otherwise maybe take it off the public internet for a bit?
I'm just reading the code here:
Why the `err` isn't carried by the error message? For security? Then maybe log it internally?User/operator can't really fix the problem if you keep giving them information this vague.
Relevant change:
``` This git endpoint is seeing a high influx of requests for this repository, to preserve the availability of Codeberg your search request will not be processed. Sorry for the inconvenience and please try again later. ```
Any mirror?
Wonder how long it took from report to patch. IME codeberg has one of the rudest security teams in oss (fair enough or not, irrelevant). https://news.ycombinator.com/item?id=47941590 Is quite relevant
Removing .git after expansion seems fragile. Sandboxing the git step would close the whole class of bugs.
For those on version 15 LTS, this fix was released with v15.0.8.
I'm working on a tool to reproduce stuff like this exactly.
Yep this is an RCE with the forgejo user on the host.
https://www.pruva.dev/reproductions/REPRO-2026-00345 for details.
you can even start your version of the repro using github codespaces
========================================
REPRO-2026-00345
========================================
Title: Forgejo <16.0.4 RCE via crafted template repository (.forgejo/template expansion recreates .git folder adopted by git init)
Severity: CRITICAL
CVE: CVE-2026-89094
========================================
[pruva] Working directory: /workspaces/pruva-sandbox/pruva-results/REPRO-2026-00345
[pruva] Found script artifact: bundle/repro/reproduction_steps.sh
[pruva] Downloaded 4 repro artifact(s), script: 324 lines
[pruva] ==========================================
[pruva] WARNING: This will execute code that
[pruva] exploits a real vulnerability.
[pruva] ==========================================
[pruva] Auto-confirming in sandbox environment...
[pruva] Running reproduction script...
--- REPRODUCTION OUTPUT ---
[09:39:29] ensuring container images are present
[09:39:42] vulnerable image digest: sha256:214f4ae63ee78be1e445e58573c88dc7215e72091210852e0df94eaac1a25685
[09:39:42] fixed image digest: sha256:a263a1298e89e0bdf019005ce1927e9aadaa8f1bd2a94a3e66ad94e2a89e19ce
[09:39:42] [vuln-1] starting container (codeberg.org/forgejo/forgejo:16.0.3-rootless)
[09:39:52] [vuln-1] service healthy on 127.0.0.1:4011
[09:39:53] [vuln-1] admin user + token ready
[09:39:55] [vuln-1] malicious template pushed
[09:40:03] [vuln-1] generate API returned 201
[09:40:15] [vuln-1] marker=**** hook_id=**** hostdata=**** readme_ok=**** gen=201
[09:40:15] [vuln-2] starting container (codeberg.org/forgejo/forgejo:16.0.3-rootless)
[09:40:25] [vuln-2] service healthy on 127.0.0.1:4012
[09:40:26] [vuln-2] admin user + token ready
[09:40:28] [vuln-2] malicious template pushed
[09:40:32] [vuln-2] generate API returned 201
[09:40:36] [vuln-2] marker=**** hook_id=**** hostdata=**** readme_ok=**** gen=201
[09:40:36] [fixed-1] starting container (codeberg.org/forgejo/forgejo:16.0.4-rootless)
[09:40:40] [fixed-1] service healthy on 127.0.0.1:4111
[09:40:40] [fixed-1] admin user + token ready
[09:40:41] [fixed-1] malicious template pushed
[09:40:46] [fixed-1] generate API returned 201
[09:40:50] [fixed-1] marker=false hook_id=false hostdata=false readme_ok=**** gen=201
[09:40:50] [fixed-2] starting container (codeberg.org/forgejo/forgejo:16.0.4-rootless)
[09:40:52] [fixed-2] service healthy on 127.0.0.1:4112
[09:40:53] [fixed-2] admin user + token ready
[09:40:54] [fixed-2] malicious template pushed
[09:40:58] [fixed-2] generate API returned 201
[09:41:02] [fixed-2] marker=false hook_id=false hostdata=false readme_ok=**** gen=201
[09:41:02] vuln markers: **** / **** ; hook-id: **** / **** ; hostdata: **** / **** ; gen: 201 / 201
[09:41:02] fixed markers: false / false ; readme-ok: **** / **** ; gen: 201 / 201 runtime_manifest.json written with 44 proof artifacts
[09:41:02] VERDICT: CONFIRMED - remote code execution reproduced on Forgejo 16.0.3 via crafted template repository; fixed 16.0.4 unaffected
--- END REPRODUCTION OUTPUT ---
[pruva] ==========================================
[pruva] VERIFICATION SUCCESSFUL
[pruva] Duration: 93s
[pruva] ==========================================
[pruva] Logs: /workspaces/pruva-sandbox/pruva-results/REPRO- 2026-00345/logs/ - fixed-1 - fixed-2 - reproduction_steps.log - vuln-1 - vuln-2
[pruva] Results saved to: /workspaces/pruva-sandbox/pruva-results/REPRO-2026-00345
[pruva] Keeping work directory: /workspaces/pruva-sandbox/pruva-results/REPRO-2026-00345 Outcome: success User: vscode WorkspaceFolder: /workspaces/pruva-sandbox
The opex and security fine costs of moving off managed services like GitHub/GitLab are catching up.
If you are self-hosting Forgejo and haven't done it yet, consider creating a Codeberg account and following https://codeberg.org/forgejo/security-announcements/issues
This is why I prefer simpler setups for personal use/hosting. Something like cgit that has no accounts has much less surface area for this kind of issue.
What does the error message mean by "Your search request"? Why is viewing a single file in a repository considered a search request? That smells like poor caching somewhere
Can't load the page but hopefully it's on an endpoint sitting behind my Tinyauth protection.
Glad I have my Forgejo service set to auto update.
Quick note that this is not an RCE in the typical sense that I can rock up to a Forgejo installation and execute code on the server. The attack vector here is via a template repo specified when initializing a new repo. The template repo could contain malicious code that then executes on the host server. So if you don't create new repos from mystery meat template repos, you should be ok.
Trying to open any codeberg.org page from my main Helium browser results in a 403 just saying "Bye". Opening in Chrome or Firefox works fine. Very confusing.
As I said before for patching vulnerabilities in the age of AI [0], attackers are going to build exploits around this RCE with AI or even find more flaws with AI.
This means you have no choice but to use AI to defend, find and patch these flaws before attackers quickly build and use these exploits to target users.
You cannot afford to disallow or have a 100% ban on LLM contributions while attackers do not care and will use AI to find the flaws and attack you faster than you can triage it.
[0] https://news.ycombinator.com/item?id=49262849