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-hostmatcher-0001-ssrf — Forgejo 16.0.5 - High - Remote - SSRF - hostmatcher allows 0.0.0.1 as a public IP | Kitploit
Tools/GitHubGitHub/abraxas/forgejo-hostmatcher-0001-ssrf
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingRed TeamingLabs & Practice
GitHubabraxas/forgejo-hostmatcher-0001-ssrf

forgejo-hostmatcher-0001-ssrf

Forgejo 16.0.5 - High - Remote - SSRF - hostmatcher allows 0.0.0.1 as a public IP

View Repository
14 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-hostmatcher-0001-ssrf

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  forgejo-hostmatcher-0001-ssrf

forgejo-hostmatcher-0001-ssrf

Class: SSRF Reach: Remote

Forgejo 16.0.5 (8d24b7d) - Forgejo

Default [webhook] ALLOWED_HOST_LIST is empty, so services/webhook/deliver.go builds the client with builtin external. That predicate is Go IsGlobalUnicast() && !isPrivate(). isPrivate is RFC1918/4193 plus the v16.0.2 CGNAT add. RFC 6890 0.0.0.0/8 is none of those. 127.0.0.1 is loopback and denied. 0.0.0.1 is allowed.

A signed-in user can webhook http://0.0.0.1 and read the HTTP body from hook history. 127.0.0.1 on the same port is denied.

IDno CVE yet
ClassSSRF
ReachRemote (authenticated; any user who can create a repo webhook)
CWECWE-918
CVSSHigh: 7.7 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
ProductForgejo
Affectedthrough v16.0.5 (8d24b7d); leftover of the v16.0.2 CGNAT add
Authsigned-in user who can create a repo webhook
LicenseGNU Affero GPL v3.0
Lab127.0.0.1 only

What an attacker can do

Register on a default install, create a repo, set a forgejo webhook to http://0.0.0.1:<port>/..., test it, and read the response body.

PrivilegeMethod / sinkRecon / integrity / availabilityLab-proven or inferred
Dial this-network 0.0.0.1 past the default webhook allow-listPOST /api/v1/repos/{owner}/{repo}/hooks then POST .../hooks/{id}/tests with URL http://0.0.0.1:8080/ssrfRecon (outbound HTTP from the Forgejo host)Lab-proven. History stored HTTP 200 body FORGEJO-HOSTMATCHER-0001-WITNESS
Read the full HTTP response of whatever answeredGET /{owner}/{repo}/settings/hooks/{id} prints ResponseInfo.BodyRecon (full-response SSRF)Lab-proven. Same witness in the history page
Same class via IPv4-mapped [::ffff:0.0.0.1]Same matcher To4() then checkIPReconInferred from hostmatcher. Lab used 0.0.0.1
Reach a listener that bound broader than loopback in the Forgejo netnsLinux connect() to 0.0.0.0/8 is this-host once 0.0.0.1 is on loReconLab-proven against the sidecar oracle. Not a claim about a specific cloud IMDS

Closed on the same default matcher: 127.0.0.1 (lab-proven deny in history), 127.0.0.0/8, RFC1918, CGNAT 100.64.0.0/10, link-local 169.254.0.0/16 including IPv4 IMDS, unspecified 0.0.0.0. The outbound webhook does not gain X-Forgejo-Internal-Auth / INTERNAL_TOKEN. This is not RCE by itself.

This is not the v16.0.2 CGNAT fix. Forgejo never grew a Gitea-style reserved-net list. Same class as gitea-hostmatcher-0000-ssrf.

How I found it

v16.0.2 put CGNAT in private. Patches that add a deny-list are a gift: you read the list, then you ask what IANA still has that the list forgot. A sibling hunt claimed Go 1.26 IsGlobalUnicast closed 0.0.0.1. I checked the predicate and the in-tree tests. They never cover 0.0.0.1.

Wrong turns already recorded: treating webhook create HTTP 201 as the oracle (history is the oracle); 127.0.0.1 delivery succeeding (that would be a different bug - lab requires it denied); hitting /api/internal with X-Forgejo-Internal-Auth; a reverse shell. Theatre.

Lab

python3 forgejo-hostmatcher-0001-ssrf-Abraxas-Labs.py

or:

cd lab
./run.sh

Target only http://127.0.0.1:19320. Image codeberg.org/forgejo/forgejo:16.0.5. Oracle sidecar shares the Forgejo netns on port 8080.

create-hook name=neg-loopback ...
negative-control 127.0.0.1 blocked
create-hook name=hit-0001 ...
poll id=2 witness=True
SUCCESS forgejo-hostmatcher-0001-ssrf how=live pin=v16.0.5 0.0.0.1:8080 HTTP 200 FORGEJO-HOSTMATCHER-0001-WITNESS

The fix

Treat RFC 6890 0.0.0.0/8 as not-external (a reserved-net list, not IsGlobalUnicast). 0.0.0.1 must be denied the same way 127.0.0.1 is.

References

  • codeberg.org/forgejo/forgejo tag v16.0.5
  • hostmatcher.go
  • Nearby patched: v16.0.2 CGNAT
  • Same class on Gitea: gitea-hostmatcher-0000-ssrf
  • RFC 6890
  • CWE-918

License

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

Download Tool