← Back to Feed CACHED · 2026-10-14 10:21:39 · CACHE_KEY CVE-2026-89111
CVE-2026-89111 · CWE-918 · Disclosed 2026-10-13

OAuth2 SSRF via tenant_subdomain injection in SAP Cloud SDK for Python

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Like leaving your building's master key taped inside the intercom — but only if the building uses a rare brand of buzzer system

CVE-2026-89111 is a Server-Side Request Forgery in the SAP Cloud SDK for Python (sap-cloud-sdk on PyPI) affecting versions prior to 0.45.2. The SDK's OAuth2 token-request flow takes a tenant_subdomain parameter and substitutes it directly into the token endpoint URL without validation. An attacker who can control that parameter — typically via the inbound HTTP request in a multi-tenant SAP BTP application — redirects the token request to an attacker-controlled server, causing the application's OAuth2 client credentials (client ID + secret) to be sent to the attacker. The fix in 0.45.2 validates tenant_subdomain against RFC 1123 DNS label rules before URL construction. Only multi-tenant BTP applications using the Python SDK are affected; single-tenant apps and the far more prevalent Java SDK are not in scope.

SAP scored this a perfect 10.0 — and the CVSS math is technically correct: the attack is network-reachable, no auth needed, no user interaction, low complexity, and the scope change reflects credentials crossing trust boundaries. But CVSS doesn't model installed-base size. The Python SDK is SAP's *newer* cloud toolkit, launched primarily for AI agent and modern Python workloads on BTP. Compared to the Java SDK that powers the vast majority of SAP cloud applications, the Python SDK's production footprint is a small fraction. You're looking at thousands of deployments, not hundreds of thousands. The vendor severity is accurate *for the apps that use this SDK*, but calling this a universal CRITICAL overstates the blast radius for most SAP shops. noisgate downgrades to HIGH 8.6: the mechanics are real, the population is narrow.

"CVSS 10 is the right math but the wrong installed base — HIGH for most shops."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a multi-tenant BTP application using the Python SDK

The attacker needs a target application built on SAP BTP that uses sap-cloud-sdk for Python and implements multi-tenant OAuth2 flows. These applications typically expose tenant-specific subdomains (e.g., tenant1.myapp.cfapps.eu10.hana.ondemand.com). The attacker discovers the target through SAP BTP marketplace listings, subdomain enumeration, or reconnaissance of an organization's SAP cloud footprint.
Conditions required:
  • Target application uses sap-cloud-sdk for Python < 0.45.2
  • Application is multi-tenant on SAP BTP
  • Application is internet-accessible (standard for BTP)
Where this breaks in practice:
  • The Python SDK has a much smaller installed base than the Java SDK — most SAP BTP apps use Java or CAP Node.js
  • Identifying that the *Python* SDK is in use (vs. Java) requires fingerprinting or guesswork
  • Single-tenant BTP applications are not affected
Detection/coverage: No standard scanner fingerprints the SDK language behind a BTP app. Custom asset inventory of deployed BTP services and their dependency manifests is required.
STEP 02

Craft a malicious tenant_subdomain value

The attacker constructs a request to the target application that injects a malicious value into the tenant_subdomain parameter. Instead of a legitimate tenant subdomain like acme, the attacker supplies a value like evil.attacker.com or uses DNS-label tricks to redirect the URL to attacker-controlled infrastructure. The vulnerable SDK blindly substitutes this into the OAuth2 token endpoint URL template.
Conditions required:
  • The application passes attacker-controllable input to the SDK's tenant_subdomain parameter
  • Attacker has infrastructure to receive HTTPS callbacks
Where this breaks in practice:
  • Application-level input validation (if any) may reject obviously malicious subdomain values
  • Some BTP applications resolve tenant identity server-side from the request hostname, not from user-supplied parameters — these are not exploitable via this path
Detection/coverage: WAF rules inspecting for non-alphanumeric characters in tenant identification parameters could flag anomalous values. SAP BTP audit logs may capture unusual token-request destinations.
STEP 03

SDK sends credentials to attacker-controlled server

The vulnerable sap-cloud-sdk constructs the OAuth2 token endpoint URL using the poisoned tenant_subdomain and initiates an outbound HTTPS POST to the attacker's server. This POST includes the application's client_id and client_secret in the request body (standard OAuth2 client_credentials grant). The attacker captures these credentials on their server. No authentication or user interaction is required at any point.
Conditions required:
  • Outbound HTTPS from the BTP Cloud Foundry / Kyma runtime to arbitrary hosts is permitted (default)
Where this breaks in practice:
  • BTP runtimes generally allow outbound internet — there is no default egress filtering to SAP-only destinations
  • If the organization has configured BTP network policies or a cloud egress proxy, non-SAP destinations might be blocked, but this is uncommon
Detection/coverage: Monitor BTP application logs for OAuth2 token requests to non-SAP domains. Network flow logs showing outbound connections from BTP app containers to unexpected IPs are a signal.
STEP 04

Use stolen credentials to access tenant resources

With the captured OAuth2 client credentials, the attacker authenticates as the application to SAP XSUAA (the BTP authorization service) and obtains access tokens. These tokens grant whatever scopes the application's service binding was configured with — typically read/write access to SAP backend APIs including S/4HANA, SuccessFactors, or other connected systems for the targeted tenant. The attacker can now exfiltrate data or perform actions as the application.
Conditions required:
  • Stolen credentials are still valid (not rotated)
  • Application service binding has meaningful scopes
Where this breaks in practice:
  • Credential rotation after detection would invalidate stolen secrets
  • SAP XSUAA token requests from unexpected IP ranges could trigger anomaly detection if configured
Detection/coverage: SAP XSUAA audit logs showing token grants from unusual source IPs. SAP Cloud ALM or BTP Security Events can surface anomalous OAuth2 activity.
03 · Compensating Control

1
HIGH 8.6→IGNORE 0.0
SEVERITY REDUCED
Upgrade sap-cloud-sdk to ≥ 0.45.2 immediately — The definitive fix. Version 0.45.2 validates tenant_subdomain against RFC 1123 DNS label rules, preventing URL injection. Current latest is 0.58.1 — any version ≥ 0.45.2 is safe. Deploy within 30 days per the noisgate remediation SLA for HIGH. Given this is a pip dependency update with no breaking API changes, most teams can deploy in days, not weeks.
2
HIGH 8.6→LOW 2.5
SEVERITY REDUCED
Implement application-level tenant_subdomain allowlisting — If you cannot upgrade immediately, add validation in your application code before passing tenant_subdomain to the SDK. Maintain an allowlist of registered tenant subdomains and reject any value not on the list. This is a code change in your application, not the SDK, so it's independently deployable. Apply within 30 days per the noisgate mitigation SLA for HIGH.
3
HIGH 8.6→LOW 2.0
SEVERITY REDUCED
Configure BTP egress network policies to restrict outbound destinations — Restrict outbound HTTPS from your BTP Cloud Foundry or Kyma runtime to SAP-owned domains only (*.authentication.sap.hana.ondemand.com, *.ondemand.com). This prevents the SSRF from reaching attacker infrastructure even if the URL is poisoned. Implementation varies by BTP runtime — Cloud Foundry uses Application Security Groups, Kyma uses NetworkPolicies.
4
HIGH 8.6→HIGH 8.6
Rotate OAuth2 client credentials for all affected applications — If you suspect exploitation or cannot confirm your current SDK version, rotate the client_id/client_secret in SAP XSUAA for all multi-tenant Python BTP applications. This invalidates any previously stolen credentials. Coordinate with your BTP admin to avoid service disruption during rotation.
What doesn't work
  • WAF rules alone — The malicious tenant_subdomain value is a legitimate-looking DNS label (e.g., evil.attacker.com). Standard WAF signatures for SSRF (looking for http://, file://, or internal IPs) won't catch DNS-based redirections. WAF helps at the margins but cannot substitute for SDK-level validation.
  • SAP BTP API Management gateway — The SSRF is an outbound request from the application, not an inbound API call. API management gateways sit in front of inbound traffic and do not inspect or control the SDK's outbound OAuth2 token requests.
  • Upgrading the Java SDK — Only the Python SDK (sap-cloud-sdk on PyPI) is affected. If your BTP applications use the Java SDK (com.sap.cloud.sdk), they are not vulnerable to this CVE. Do not waste cycles auditing Java apps for this issue.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNot observed. Not listed on CISA KEV. No campaigns reported by SAP, BleepingComputer, or threat intelligence vendors as of 2026-10-14. SAP advisory states no known exploitation.
Proof-of-concept availabilityNo public PoC. Not indexed on pocindex.io, no CVE-named repos on GitHub, no ExploitDB or nuclei templates found. The exploit is conceptually simple (parameter injection into a URL template) but no weaponized tooling exists publicly.
EPSS score0.00274 (0.27%) — very low exploitation probability. Sits well below the 90th percentile threshold. Reflects the niche installed base and absence of exploit tooling.
KEV statusNot listed on CISA Known Exploited Vulnerabilities catalog as of 2026-10-14.
CVSS vector interpretationCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N — Perfect exploitability sub-score (3.9). Scope Changed reflects credentials crossing the application trust boundary. No availability impact because the attack is silent credential theft, not disruption.
Affected versionssap-cloud-sdk (PyPI) < 0.45.2. Only multi-tenant SAP BTP applications using the Python SDK's OAuth2 token-request flow are vulnerable.
Fixed version0.45.2 (released ~August 2026, CVE assigned October 13, 2026). Current latest is 0.58.1. The fix validates tenant_subdomain against RFC 1123 DNS label rules.
Scanning / exposure dataNo GreyNoise or Shodan tags exist for this CVE. BTP applications are cloud-hosted on SAP infrastructure; Shodan/Censys visibility is limited to the SAP CF/Kyma ingress layer, not individual SDK versions.
Disclosure timeline2026-10-13: SAP Security Patch Day, GitHub Security Advisory GHSA-4mv3-jxxm-9cx2 published. Silent fix shipped in 0.45.2 weeks earlier.
Reporting researcherNot publicly attributed. Advisory published by [email protected] (SAP as CNA). No external researcher credited in the GHSA or SAP advisory.

Sources.

  1. GitHub Security Advisory GHSA-4mv3-jxxm-9cx2
  2. BleepingComputer — SAP warns of maximum severity OAuth2 SSRF flaw
  3. SAP Security Patch Day October 2026 — SecurityOnline
  4. Rescana — CVE-2026-89111 SSRF Analysis
  5. Strix.ai — CVE-2026-89111 Details and Fix
  6. sap-cloud-sdk on PyPI
  7. SAP Cloud SDK for Python — GitHub Repository
05 · The Call

Final Verdict
↓ DOWNGRADED to HIGH (8.6/10)

Why this verdict

  • CVSS math is correct but context-blind. The 10.0 score accurately models the attack mechanics for a vulnerable multi-tenant Python BTP app. But CVSS does not penalize for installed-base size. The SAP Cloud SDK for Python is a *newer* toolkit with a fraction of the Java SDK's deployment footprint — likely low thousands of production multi-tenant applications globally vs. the Java SDK's tens of thousands.
  • No exploitation evidence compounds the narrowing. EPSS is 0.27%, no KEV listing, no PoC, no in-the-wild activity. For a CVE disclosed yesterday (2026-10-13) this is expected, but it means there is no urgency multiplier to offset the limited blast radius.
  • Multi-tenant requirement further narrows scope. Only BTP applications explicitly configured for multi-tenancy and using the Python SDK's OAuth2 flow are affected. Single-tenant applications, applications using the Java SDK, and applications that resolve tenant identity server-side from trusted sources are not in the attack path.
  • Unauthenticated remote exploitation keeps the floor at HIGH. Despite the narrow population, the attack requires zero privileges, zero user interaction, and has low complexity. When conditions are met, credential theft is trivial and silent. This prevents a downgrade below HIGH.
  • Role multiplier: SAP BTP applications occupy a business-critical role — they typically integrate with S/4HANA, SuccessFactors, Ariba, and other core enterprise systems. Stolen OAuth2 credentials grant application-level access to tenant backend data (financials, HR, procurement). The blast radius per-exploitation is tenant-level data egress, not fleet or domain takeover. Because the affected component is a cloud SDK library (not core infrastructure like an IdP, hypervisor, or DC), and because each tenant requires separate exploitation, the blast radius does not reach the CRITICAL floor. However, in organizations where a single multi-tenant SaaS app serves dozens of enterprise customers, one exploitation could expose multiple tenants' SAP data — this anchors the verdict firmly at HIGH.

Why not higher?

The CRITICAL floor requires that the affected component canonically occupies a high-value infrastructure role (IdP, hypervisor, DC, PAM, CA, backup) OR that exploitation produces fleet/domain/supply-chain-scale impact. The SAP Cloud SDK for Python is an application-layer library, not infrastructure. Each exploitation yields one tenant's credentials, not fleet-wide compromise. The installed base is a small fraction of the SAP ecosystem, and no evidence of exploitation or tooling exists to suggest imminent mass targeting. These factors collectively prevent a CRITICAL rating.

Why not lower?

The attack is fully unauthenticated, network-accessible, and requires no user interaction — the holy trinity of exploitability. The credential theft is silent and immediately actionable (attacker gets working OAuth2 secrets). BTP applications handle genuinely sensitive enterprise data. Even though the population is narrow, the *per-instance impact* is severe: an attacker with client credentials can impersonate the application and access backend SAP systems. A MEDIUM rating would understate the risk for the organizations that DO run multi-tenant Python BTP apps.

06 · Verification

Crowdsourced verification payload.

Run this script on any host where SAP BTP Python applications are developed or deployed — typically your CI/CD runner or the BTP Cloud Foundry app container. Invoke with python3 check_cve_2026_89111.py. No elevated privileges required; it checks the installed pip package version.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
"""CVE-2026-89111 checker — SAP Cloud SDK for Python OAuth2 SSRF
Checks whether the installed sap-cloud-sdk version is vulnerable.
Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
"""
import sys
import importlib.metadata

FIXED_VERSION = (0, 45, 2)

def parse_version(v):
    """Parse a PEP-440 version string into a comparable tuple."""
    parts = []
    for segment in v.split('.'):
        try:
            parts.append(int(segment.split('a')[0].split('b')[0].split('rc')[0].split('dev')[0]))
        except ValueError:
            parts.append(0)
    return tuple(parts)

try:
    version_str = importlib.metadata.version('sap-cloud-sdk')
except importlib.metadata.PackageNotFoundError:
    print('[UNKNOWN] sap-cloud-sdk is not installed in this Python environment.')
    print('If this host does not run SAP BTP Python applications, this check is not applicable.')
    sys.exit(2)

installed = parse_version(version_str)

print(f'Installed sap-cloud-sdk version: {version_str}')
print(f'Fixed version: {".".join(str(x) for x in FIXED_VERSION)}')

if installed < FIXED_VERSION:
    print(f'[VULNERABLE] sap-cloud-sdk {version_str} is affected by CVE-2026-89111.')
    print('Action: upgrade to >= 0.45.2 with: pip install --upgrade sap-cloud-sdk')
    sys.exit(1)
else:
    print(f'[PATCHED] sap-cloud-sdk {version_str} includes the CVE-2026-89111 fix.')
    sys.exit(0)