Strona główna / Blog / SAP Cloud SDK Python 89111

Blog · case study

SAP Cloud SDK for Python CVE-2026-89111: CVSS 10.0 w zależności pip, której SAP-owy patch management nie widzi

Na październikowym SAP Security Patch Day (13.10.2026) najwyższą ocenę dostała podatność, której nie ma w żadnym systemie SAP. CVE-2026-89111 (note 3797111, CVSS 10.0) siedzi w SAP Cloud SDK for Python, czyli w pakiecie sap-cloud-sdk z PyPI, który instalujesz w swoich aplikacjach na BTP. Kto kontroluje parametr tenant_subdomain, może skierować żądanie tokenu OAuth2 na własny serwer i przechwycić client credentials aplikacji. Tego findingu nie zamkniesz przez SNOTE. Trzeba go znaleźć w requirements.txt, w lockfile’u albo w SBOM.

CVE-2026-89111 (SAP note 3797111, GHSA-4mv3-jxxm-9cx2): „OAuth2 SSRF vulnerability in SAP Cloud SDK for Python”. CVSS 3.1 AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N = 10.0, CWE-918.
Pakiet: PyPI sap-cloud-sdk (moduł sap_cloud_sdk, repozytorium SAP/cloud-sdk-python). Podatne < 0.45.2, poprawione w 0.45.2. Tak podają jednocześnie strona Patch Day, NVD i advisory w repozytorium SAP („patched_versions: 0.45.2”).
Kogo dotyczy: aplikacje multi-tenant na SAP BTP, w których atakujący może wpłynąć na wartość tenant_subdomain przekazywaną do SDK.
Threat state (16.10): SAP nie podaje informacji o eksploatacji, CVE nie ma w KEV. CISA SSVC w NVD: exploitation none, automatable yes, technical impact total.

Attack path

attacker controls tenant_subdomain (e.g. value derived from request / tenant context) -> SDK substitutes it into the OAuth2 token URL without validation -> token request (with the app's client credentials) goes to attacker host -> client credentials exfiltrated -> attacker requests tokens as the application (scope: changed)

Advisory jest krótkie: kto kontroluje tenant_subdomain, może przekierować żądania tokenu OAuth2 na serwer, który sam kontroluje, a to prowadzi do wycieku client credentials. Release notes wersji 0.45.2 dopowiadają, które miejsca poprawiono: AgentGatewayClient._resolve_tenant_subdomain, destination.TokenProvider.get_token i dms.Auth._resolve_token_url. Wartość jest teraz sprawdzana według reguł etykiety DNS z RFC 1123, a kropki, ukośniki, spacje, podkreślenia i ciągi dłuższe niż 63 znaki kończą się błędem ValueError. Wcześniej, jak piszą sami autorzy, nieprawidłowe wartości były „silently used to construct a malformed URL”. Wniosek dla VE: punktem wejścia jest nie SDK samo w sobie, tylko to, skąd Twoja aplikacja bierze subdomenę tenanta. Mechanizm przypomina znany z LiteLLM wzorzec, w którym klient sam dołącza sekrety do żądania wysłanego pod adres podany przez atakującego.

Dlaczego klasyczny proces SAP tego nie zobaczy

W wielu organizacjach patch management SAP wygląda tak: co miesiąc lista SAP notes, dopasowanie do komponentów i Support Package’ów, wdrożenie przez SNOTE albo SPAM/SUM. Ten proces działa na systemach. CVE-2026-89111 nie dotyczy żadnego systemu: to biblioteka zainstalowana przez pip w aplikacji, którą napisał Twój zespół albo partner, zbudowana w Twoim CI i wdrożona na Cloud Foundry lub Kyma. Note 3797111 nie ma czego „zaimplementować” w systemie SAP. Właścicielem findingu jest więc zespół aplikacji, a nie Basis, a skaner infrastruktury nie zajrzy do obrazu kontenera ani do lockfile’a w repozytorium.

Jest jeszcze druga pułapka, tym razem po stronie SCA. Według danych pobranych 16.10 baza GitHub Advisory ma dla tego CVE globalny rekord GHSA-m3j7-wp2j-mhc3, który jest „unreviewed” i ma pustą listę podatnych pakietów. Rekord z prawdziwym zakresem wersji (pip / sap-cloud-sdk / <0.45.2) to advisory w repozytorium SAP, czyli GHSA-4mv3-jxxm-9cx2. Zapytanie do OSV o sap-cloud-sdk 0.45.1 (PyPI) zwraca pusty wynik, a sam rekord OSV dla CVE-2026-89111 ma zakres zapisany jako tekst "sap-cloud-sdk < 0.45.2" zamiast wersji pakietu. PyPI też nie pokazuje podatności przy wersji 0.45.1. W praktyce narzędzia opierające się na tych źródłach mogą na razie nie zgłosić podatnej wersji. Nie sprawdzałem każdego skanera, ale „Dependabot milczy” nie dowodzi tu, że problemu nie ma. Ten sam rozjazd między GHSA a resztą ekosystemu opisywałem przy Flatpaku i h3.

Jak znaleźć pakiet

Dopóki bazy SCA nie mają poprawnego zakresu wersji, szukaj nazwy pakietu i porównuj wersję ręcznie. Pip normalizuje nazwy, więc w plikach może się pojawić sap-cloud-sdk, sap_cloud_sdk albo SAP-Cloud-SDK.

# w działającym środowisku / obrazie aplikacji pip show sap-cloud-sdk # Version: < 0.45.2 = podatne pip list 2>/dev/null | grep -i "sap.cloud.sdk" # w repozytoriach: manifesty i lockfile'y grep -rniE "sap[-_.]cloud[-_.]sdk" --include="requirements*.txt" \ --include="pyproject.toml" --include="poetry.lock" --include="uv.lock" \ --include="Pipfile*" --include="setup.cfg" --include="setup.py" . # w SBOM (CycloneDX / SPDX): purl grep -rhoiE "pkg:pypi/sap[-_.]cloud[-_.]sdk@[0-9.]+" sboms/ | sort | uniq -c

Uwaga na zapisy bez górnego limitu, np. sap-cloud-sdk>=0.40 w requirements.txt: wersję w produkcji wyznacza wtedy lockfile albo dzień ostatniego buildu, a nie manifest. Jeśli nie masz lockfile’a, sprawdzaj obraz, który faktycznie działa. To samo zjawisko, tylko w ekosystemie NPM, opisywałem przy SAP CAP multitenancy: biblioteka od SAP w aplikacji klienta potrafi stać się cross-tenant findingiem.

Remediation

Poprawka: sap-cloud-sdk 0.45.2 lub nowszy (na PyPI aktualna jest 0.59.0). Wymagany Python >= 3.11.
Od kiedy: 0.45.2 trafiło na PyPI 21.08.2026, prawie dwa miesiące przed advisory. Release notes opisują zmianę jako „Bug Fixes”, bez słowa o bezpieczeństwie. Zespoły, które regularnie podbijają zależności, mogą więc być już poprawione. Pinowane wersje sprzed tej daty nie są.
Workaround (SAP): aplikacja przed każdym wywołaniem SDK sprawdza tenant_subdomain względem allowlisty zarejestrowanych subdomen tenantów. Advisory nie podaje innych środków zaradczych.

Workaround to zmiana w kodzie aplikacji, nie konfiguracja platformy. Wymaga więc przeglądu wszystkich miejsc, w których subdomena trafia do SDK. W praktyce upgrade jest zwykle prostszy. Allowlista ma sens tam, gdzie upgrade blokuje zgodność z innymi pakietami.

Rotacja sekretów to osobna decyzja

Upgrade zamyka podatność, ale nie unieważnia credentials, które mogły już wyciec. SAP nie zaleca rotacji wprost, w advisory jej nie ma. Skutkiem podatności jest jednak właśnie wyciek client credentials, a advisory nie podaje IoC. Jeśli więc aplikacja z podatną wersją działała w trybie multi-tenant, a tenant_subdomain mógł pochodzić z danych kontrolowanych z zewnątrz, rozsądnie jest założyć ekspozycję. Rotuj client secrets / klucze service bindings, których SDK używało do pobierania tokenów, i przejrzyj logi ruchu wychodzącego z aplikacji pod kątem żądań tokenów do hostów spoza oczekiwanych domen. Taki „kontekst sekretów” przy SSRF omawiałem przy AWX.

Na marginesie: CVE-2026-89110, Visual Composer 9.9

Ten sam Patch Day przyniósł też CVE-2026-89110 (note 3805589, CVSS 9.9, Broken Access Control) w SAP NetWeaver Visual Composer, VC70RUNTIME 7.50. Według NVD użytkownik o niskich uprawnieniach może wywołać wewnętrzne operacje na wcześniej skonfigurowanym systemie zdalnym, co zależnie od konfiguracji połączenia może skończyć się pełnym przejęciem tego systemu. To klasyczny finding po stronie systemu SAP, więc ten proces miesięczny zobaczy. Ciekawostka z jakości danych: rekord NVD dla 89110 w referencjach linkuje note 3797111 (czyli note od SDK), podczas gdy strona SAP Patch Day przypisuje 89110 do note 3805589. Przy automatycznym mapowaniu CVE→note trzymaj się strony SAP.

Co powinien zrobić VE

(1) Przeszukaj repozytoria, lockfile’y, SBOM-y i działające obrazy pod kątem sap-cloud-sdk i zapisz wersję każdej instancji. Nie czekaj, aż alert pojawi się sam. (2) Każdą aplikację z wersją < 0.45.2 przypisz do zespołu aplikacyjnego, nie do Basis. (3) Ustal, czy aplikacja jest multi-tenant i skąd bierze tenant_subdomain. To decyduje o priorytecie. (4) Upgrade do 0.45.2+, a do tego czasu allowlista według advisory SAP. (5) Przy realnej ekspozycji rotuj credentials. (6) Dodaj „biblioteki SAP w ekosystemach pip/npm/Maven” jako osobną kategorię w przeglądzie każdego SAP Patch Day. Strona SAP oznacza je wprost jako „Library” i osobno wylicza GitHub security advisories.

Powiązane na blogu

Źródła

  • SAP Security Patch Day — October 2026 (13.10.2026) — support.sap.com
  • SAP/cloud-sdk-python — GHSA-4mv3-jxxm-9cx2: OAuth2 SSRF vulnerability in SAP Cloud SDK for Python — github.com
  • SAP/cloud-sdk-python — release v0.45.2 (21.08.2026) — github.com
  • PyPI — sap-cloud-sdk — pypi.org
  • NVD — CVE-2026-89111 — nvd.nist.gov
  • GitHub Advisory Database — GHSA-m3j7-wp2j-mhc3 (unreviewed) — github.com
  • OSV — CVE-2026-89111 — osv.dev
  • NVD — CVE-2026-89110 (SAP NetWeaver Visual Composer) — nvd.nist.gov

Nota redakcyjna: stan informacji 16 października 2026, na podstawie strony SAP Security Patch Day (13.10.2026), advisory GHSA-4mv3-jxxm-9cx2 w repozytorium SAP/cloud-sdk-python, release notes v0.45.2, PyPI, NVD i OSV. Treść SAP note 3797111 wymaga logowania do SAP for Me i nie była weryfikowana. Stan rekordów GitHub Advisory Database i OSV może się zmienić po ich przeglądzie. Zalecenie rotacji credentials to rekomendacja autora, nie zalecenie SAP.

Zapamiętaj jedno

CVSS 10.0 z SAP Patch Day nie zawsze trafia do Basis. Gdy komponent oznaczony jest jako „Library”, finding żyje w lockfile’u Twojej aplikacji. Wykrywa go inwentarz zależności, nie lista SAP notes. A gdy bazy SCA nie mają jeszcze poprawnego zakresu wersji, wystarczy zwykły grep po nazwie pakietu.