Repository navigation
Conversation
DestinationHttpClient pre-bakes destination credentials (auth tokens, API keys, x-sap-* headers) into a persistent requests.Session. Because requests followed 3xx redirects automatically, those headers were silently forwarded to the redirect target — potentially a different origin. Changes: - DestinationHttpClient.request() now defaults to RedirectMode.NONE, which returns the 3xx response as-is without following it. This is automatic: no changes are required in consuming code. - New RedirectMode.SAME_ORIGIN opt-in follows redirects only when the Location URL has the same scheme, host, and effective port. Cross-origin, port-change, HTTPS→HTTP, and userinfo redirects are rejected. Bounded at 5 hops. 303 See Other converts to GET and drops the body. - allow_redirects kwarg is silently stripped from request() — redirect behavior is controlled only through redirect_mode. - HttpClient._execute() (internal SAP service client) also sets allow_redirects=False to protect per-request Authorization headers. - RedirectMode exported from sap_cloud_sdk.destination. Tests: 22 new cases covering NONE/SAME_ORIGIN, all 3xx codes, credential non-leakage, chain limits, HTTPS→HTTP rejection, and 303 body drop.
- Revert pyproject.toml version 0.63.0 → 0.62.0 (version managed by release pipeline) - Update CHANGELOG to [Unreleased] section (version assigned at release time) - Fix ruff-format: expand DestinationHttpClient/RedirectMode import to multi-line
tiagoek
marked this pull request as ready for review
October 21, 2026 18:38
Remove `call` from the redirect test imports — only `call_count` and `call_args_list` are used; `call` itself was never referenced.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
DestinationHttpClientpre-baked destination credentials (auth tokens, API keys,x-sap-*headers) into a persistentrequests.Session. Becauserequestsfollows 3xx redirects by default, those headers were silently forwarded to the redirect target — potentially a different origin, leaking credentials.The default is now
RedirectMode.NONE— redirects are not followed. This is automatic: no changes are required in consuming code.New
RedirectMode.SAME_ORIGINopt-in follows same-origin relative redirects only (same scheme + host + effective port). Cross-origin, port-change, HTTPS→HTTP downgrades, and userinfo inLocationare rejected. Hop count is bounded at 5. HTTP 303 converts to GET and drops the body.HttpClient._execute()(internal SAP service client used by Destination, AI Core, and others) also setsallow_redirects=False.allow_redirects=Truein**kwargsis silently stripped — useredirect_modeinstead.RedirectModeis now exported fromsap_cloud_sdk.destination.Related Issue
No linked issue — this is a security fix.
Type of Change
How to Test
.venv/bin/python -m pytest tests/destination/unit/test_destination_http_client.py -v -k "Redirect"RedirectModeis importable from the public API:DestinationHttpClientconstructed without arguments returns a 3xx response as-is instead of following it.Checklist
/security-reviewand addressed all ❌ findingsBreaking Changes
What changes:
DestinationHttpClient.request()previously followed HTTP redirects transparently (defaultrequestsbehavior). After this change, redirect responses (3xx) are returned directly without following theLocationheader.Impact: Any application that relied on the SDK transparently following redirects will now receive the 3xx response. Inspection of production call sites confirmed zero consumers use
request()orallow_redirects, so real-world impact is minimal.Migration path: To restore same-origin redirect following:
Alternatives considered: Header-stripping on cross-origin hops — rejected because it creates a selective allow-list that is easy to misconfigure and still leaks non-
Authorizationheaders (e.g.apiKey,x-sap-security-session).Additional Notes
This PR was developed with AI assistance (Claude). See the SAP AI contribution guideline for the applicable requirements.
What changed
_destination_http_client.py:RedirectModeenum,_parse_originhelper, redirect enforcement inrequest(),_request_following_same_origin()private method__init__.py: exportsRedirectModecore/protocol/http/client.py:allow_redirects=Falsein_execute()user-guide.md: new "Redirect behavior (security boundary)" sectionCHANGELOG.md: new file documenting the behavioral change under[Unreleased]pyproject.toml: version unchanged (managed by release pipeline)Test coverage
NONE/SAME_ORIGIN, all 3xx codes, credential non-leakage, redirect chains, HTTPS→HTTP rejection, 303 body drop,allow_redirectskwarg strippingHttpClient._execute()assertingallow_redirects=False