
Gitea before 1.27.1 allows remote code execution via the diffpatch API through Git hook installation.
[!WARNING] This repository is intended exclusively for authorized security research and controlled laboratory testing. Do not run the proof of concept against systems you do not own or have explicit permission to assess.
CVE-2026-60004 is a critical remote code execution vulnerability in Gitea's diffpatch API. An authenticated user with permission to create or write to a repository can submit a crafted patch that causes an executable Git hook to be materialized inside a temporary bare repository. When the hook is triggered, attacker-controlled commands execute with the privileges of the Gitea service account.
If public registration is enabled, an unauthenticated attacker may be able to create an account and reach the vulnerable authenticated endpoint.
| Attribute | Details |
|---|
| Identifier | CVE-2026-60004 |
| Advisory | GHSA-rcr6-4jqh-j84m |
| Severity | Critical — CVSS 3.1: 9.8 |
| Weakness | CWE-94: Improper Control of Generation of Code |
| Affected versions | Gitea 1.17.0 through 1.27.0 |
| Fixed version | Gitea 1.27.1 |
| Required access | Repository write access |
| Execution context | Gitea operating-system account |
| CISA KEV date | 2026-08-25 |
| File | Description |
|---|---|
gitea_diffpatch_rce.py | Standard-library-only proof of concept that authenticates, creates a private repository, submits the crafted patch, and retrieves command output. |
payload.patch | Example patch that creates an executable hooks/post-index-change hook. |
poc.png | Screenshot captured during laboratory validation. |
README.md | Original research notes. |
The proof of concept was validated in the following isolated environment:
| Component | Configuration |
|---|---|
| Gitea | 1.27.0 |
| Git | 2.47.2 |
| Deployment | Docker container named gitea-lab |
| Service address | 192.168.184.128:3000 |
| Observed identity | uid=1000(git) gid=1000(git) |
Successful exploitation produced command output similar to:
uid=1000(git) gid=1000(git) groups=1000(git)
Linux 6.12.20-amd64 x86_64
/data/gitea/tmp/local-repo/upload.git630501597
[exit-status=0]

The script uses only Python's standard library and does not require additional packages.
python3 gitea_diffpatch_rce.py <base_url> <username> <password> "<command>"
Example for a local laboratory instance:
python3 gitea_diffpatch_rce.py \
http://127.0.0.1:3000 \
pocuser \
'P@ssw0rd!' \
'id; uname -a'
The script first attempts web registration, then authenticates with the supplied credentials. This allows the same command to work with either a new account on an instance with open registration or an existing account.
The exploitation chain consists of four stages:
Attacker-controlled patch submission
POST /api/v1/repos/{owner}/{repo}/diffpatch applies supplied patch content
using git apply --index --recount --cached --binary --ignore-whitespace --whitespace=fix -3 within a temporary clone.
Hook path placement
The temporary repository is created as a bare, shared clone. In a bare
repository, the repository root is also $GIT_DIR; consequently, the patch
path hooks/post-index-change resolves inside Git's active hooks directory.
Executable hook materialization
The same patch is submitted twice. The second application produces an
add/add conflict, causing the three-way fallback to materialize the path on
disk with mode 100755, despite the use of --cached. A subsequent index
update invokes post-index-change, executing the injected shell code as the
Gitea service account.
Git-native output retrieval
The hook identifies the origin repository through
objects/info/alternates, stores command output as a Git blob, creates a
tree and commit, and updates refs/heads/output-leak. The proof of concept
then retrieves the result through Gitea's raw-file API. This technique does
not require a direct outbound connection from the target.
Successful exploitation grants command execution with the privileges of the Gitea service account. Depending on deployment configuration, an attacker may be able to access:
app.ini and database credentialsSECRET_KEY, INTERNAL_TOKEN, and LFS-related secretsThe laboratory account was confirmed to have read access to app.ini.
Defenders should investigate the following artifacts and request patterns:
/api/v1/repos/*/*/diffpatch in quick successionoutput-leakpoc <[email protected]>hooks/post-index-change in bare
repositories or temporary clone directories/data/gitea/tmp/local-repo/upload.git*These indicators describe the included proof of concept and are not exhaustive; a modified exploit may use different paths, refs, identities, or output channels.
/api/v1/.../diffpatch
routes. Validate the rule against legitimate integrations before deployment.DISABLE_REGISTRATION=true if it
is not operationally required. This reduces unauthenticated reachability but
does not protect against existing users with repository write access.For the laboratory container used in this research, teardown can be performed with:
docker rm -f gitea-lab
This material is provided to help defenders reproduce, understand, detect, and remediate the vulnerability. Operators should test only in isolated environments and follow their organization's authorization and disclosure requirements.