Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
forgejo-restore-file-open — Forgejo 16.0.5 - High - Remote - File read - restore-repo follows dump-side file:// into attachments | Kitploit
Tools/GitHubGitHub/abraxas/forgejo-restore-file-open
Vulnerability AnalysisExploitationWeb Application ExploitationInformation GatheringPenetration TestingLabs & Practice
GitHubabraxas/forgejo-restore-file-open

forgejo-restore-file-open

Forgejo 16.0.5 - High - Remote - File read - restore-repo follows dump-side file:// into attachments

View Repository
33 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Abraxas Labs - forgejo-restore-file-open

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  forgejo-restore-file-open

forgejo-restore-file-open

Class: File read Reach: Local

Forgejo 16.0.5 (8d24b7d) - Forgejo

forgejo restore-repo of an untrusted dump rewrites release asset URLs with raw filepath.Join(baseDir, download_url) and prefixes file://. uri.Open still os.Opens that path. Empty --units restores releases. Gitea 1.27.0 added localFileURL and skipped escaping entries. That helper is not here.

Operator restore of an untrusted dump copies a host file the forgejo uid can open into a release attachment.

IDno CVE yet
ClassFile read
ReachLocal (operator forgejo restore-repo of an untrusted dump)
CWECWE-22 / CWE-73
CVSSHigh: 7.3 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N
ProductForgejo
Affectedthrough v16.0.5 (8d24b7d); local operator restore
Authlocal operator restore of an untrusted dump
LicenseGNU Affero GPL v3.0
Lab127.0.0.1 only

What an attacker can do

Hand the operator a dump directory (or already have INTERNAL_TOKEN and a path the server can read). Units include releases / release_assets.

PrivilegeMethod / sinkRecon / integrity / availabilityLab-proven or inferred
Read a host file the forgejo uid can open, via .. out of the dumprelease.yml download_url: ../FORGEJO-FILE-WITNESS.txt; restore joins, uri.Open os.Opens, bytes stored as witness.txtRecon (host-file confidentiality)Lab-proven. Attachment body is FORGEJO-RESTORE-FILE-OPEN-WITNESS. In-dump decoy INSIDE-DUMP-NOT-HOST was not served
Same result with a symlink planted inside the dumpJoined path stays under baseDir; os.Open follows the linkReconInferred from uri.Open file -> os.Open. Lab used .., not a symlink
Same sink on PR patchespull_request.yml PatchURL is rewritten the same way, then uri.Open into repo/pulls/<n>.patchReconInferred from restore.go GetPullRequests. Lab restored releases only
Readers of the restored repo download the host fileGET /<owner>/<repo>/releases/download/<tag>/<name>ReconLab-proven as labadmin Basic on the restored public repo
Typical host files: app.ini, INTERNAL_TOKEN, SECRET_KEY, DB passwordforgejo uid can read the config treeReconInferred. Lab witness was a planted file next to the dump, not live secrets

Closed here: live POST /repos/migrate file:// LFI (DownloadFunc set; PR PatchURL prefix-checked against the clone HTTP base). Absolute DownloadURL dump-root join escape (Go filepath.Join("/dump", "/etc/passwd") stays /dump/etc/passwd). Unauth HTTP restore (CLI / internal token only). Backup dump packing app.ini (secrets by design, archive mode 0600). Not OS LPE. Not remote LFI.

How I found it

I had two restore ideas. I labbed the Gitea absolute-join first in my head. Go filepath.Join does not drop an absolute second argument the way Python os.path.join does. The working input is relative ... Gitea's localFileURL is not in this tree.

Wrong turns already recorded: dump-root join escape via an absolute DownloadURL; live migrate file:// LFI; X-Forgejo-Internal-Auth (restore is CLI as the forgejo uid, not /api/internal); treating restore HTTP as remote unauth; a reverse shell. Theatre.

Lab

python3 forgejo-restore-file-open-Abraxas-Labs.py

or:

cd lab
./run.sh

Target only http://127.0.0.1:19340. Image codeberg.org/forgejo/forgejo:16.0.5. Witness FORGEJO-RESTORE-FILE-OPEN-WITNESS.

IOC asset name='witness.txt' ...
IOC download status=200 bytes=34 snippet=b'FORGEJO-RESTORE-FILE-OPEN-WITNESS\n'
SUCCESS forgejo-restore-file-open how=live ..-join file:// os.Open FORGEJO-RESTORE-FILE-OPEN-WITNESS

The fix

Contain joined paths under baseDir after EvalSymlinks (Gitea PR 38215 localFileURL). Refuse ... Do not follow dump-side symlinks out of the dump. Drop file:// from uri.Open except a dump-rooted helper.

References

  • codeberg.org/forgejo/forgejo tag v16.0.5
  • restore.go · uri.go
  • Same class on Gitea: gitea-restore-file-open
  • CWE-22 · CWE-73

License

GNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.

Download Tool