[confidentialledger] Enforce stricter redirect destination policy#49391
Open
ryazhang-microsoft wants to merge 1 commit into
Open
[confidentialledger] Enforce stricter redirect destination policy#49391ryazhang-microsoft wants to merge 1 commit into
ryazhang-microsoft wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens redirect handling in azure-security-confidentialledger by enforcing a strict redirect destination policy for ConfidentialLedgerRedirectPolicy, preventing redirects (and therefore Authorization header forwarding) to non-original-host or non-subdomain targets and to scheme-downgraded destinations.
Changes:
- Enforces redirect allow-listing based on the pristine original request URL (same scheme + same host or subdomain), refusing disallowed redirect targets and logging at warning level.
- Updates unit tests to assert that disallowed redirects are not followed (the 307 is returned as-is and the disallowed host is never contacted), including a multi-hop subdomain case.
- Adds a CHANGELOG entry describing the redirect-policy hardening.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| sdk/confidentialledger/azure-security-confidentialledger/src/main/java/com/azure/security/confidentialledger/ConfidentialLedgerRedirectPolicy.java | Enforces stricter redirect destination validation and only preserves auth on allowed redirects. |
| sdk/confidentialledger/azure-security-confidentialledger/src/test/java/com/azure/security/confidentialledger/ConfidentialLedgerRedirectPolicyTest.java | Updates and expands tests to validate refusal behavior and original-host-based multi-hop validation. |
| sdk/confidentialledger/azure-security-confidentialledger/CHANGELOG.md | Documents the behavioral hardening in the package changelog. |
| # Release History | ||
|
|
||
| ## 1.1.0-beta.3 (Unreleased) | ||
| ## 1.1.0-beta.3 (2026-06-05) |
Comment on lines
237
to
239
| } catch (MalformedURLException e) { | ||
| LOGGER.atWarning().log("Failed to parse URL for trusted redirect check; stripping Authorization header."); | ||
| LOGGER.atWarning().log("Failed to parse URL for redirect destination check; refusing to follow redirect."); | ||
| return false; |
Hardens the data-plane redirect handling in ConfidentialLedgerRedirectPolicy so the client only follows HTTP redirects whose target host is the original ledger host or one of its subdomains (using the same scheme). Redirects to sibling ledgers, parent domains, unrelated hosts, or look-alike suffix domains are now refused: they are logged at the warning level and never followed, so the sensitive Authorization header is never forwarded to an unintended destination. Previously such cross-origin redirects were followed with the Authorization header merely stripped; a misconfigured or malicious load balancer could still redirect a request to an unintended destination. - Validate every redirect hop against the pristine original request URL. - Refuse (do not follow) disallowed targets; preserve the legitimate load-balancer -> node (subdomain) redirect the service depends on. - Update unit tests to assert disallowed redirects are not followed, and add multi-hop subdomain coverage. - CHANGELOG entry under 1.1.0-beta.3.
ce17a4f to
94771c4
Compare
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.
Summary
Hardens the data-plane redirect handling in
azure-security-confidentialledgerso that the client only follows HTTP redirects whose target host is the original ledger host or one of its subdomains (using the same scheme). Redirects to sibling ledgers, parent domains, unrelated hosts, or look-alike suffix domains are now refused, logged at the warning level, and never followed or used.Java port of Azure/azure-sdk-for-python#47368.
Fixes ICM 31000000622491.
Problem
ConfidentialLedgerRedirectPolicyis used in place of the defaultRedirectPolicyso that write operations (POST) can be redirected from the load-balanced ledger endpoint to a specific node, preserving theAuthorizationheader across the service-managed redirect. Previously, the policy followed anyLocationtarget and merely stripped theAuthorizationheader on cross-origin redirects. Because Confidential Ledger intentionally preserves auth headers across its node redirects, a misconfigured or malicious load balancer could redirect a request — along with its sensitive headers — to an unintended destination.Policy
Given an original request to
https://test-ledger.confidential-ledger.azure.com, redirects are now evaluated as follows:https://test-ledger.confidential-ledger.azure.com/...(same host)https://node3.test-ledger.confidential-ledger.azure.com/...(subdomain / node)https://accledger-2.test-ledger.confidential-ledger.azure.com/...(subdomain / node)https://other-ledger.confidential-ledger.azure.com/...(sibling ledger)https://confidential-ledger.azure.com/...(parent domain)https://evil.example.com/...(unrelated host)https://test-ledger.confidential-ledger.azure.com.evil.com/...(suffix look-alike)http://test-ledger.confidential-ledger.azure.com/...(scheme downgrade)Changes
isAllowedRedirectTarget): requires an exact (case-insensitive) scheme match, then permits the redirect only when the target host equals the original host or is a subdomain of it (host == original || host.endsWith("." + original)). The port is ignored. Fails safe (rejects) if either URL cannot be parsed or either host is empty.Refusing to follow redirect to disallowed target.Authorizationheader continues to be forwarded on allowed redirects.1.1.0-beta.3.Testing
Unit tests (
ConfidentialLedgerRedirectPolicyTest) — 30/30 passing:https→http), unrelated host, look-alike suffix domain — the307is returned as-is and the disallowed host is never contacted.Live validation against a real ledger (
ryan-sdk-acl, AAD auth):307redirect to anaccledger-2.<ledger>.confidential-ledger.azure.comnode subdomain is followed, and writes succeed end-to-end (single write/commit/read round-trip and 15 consecutive writes).307whoseLocationis rewritten toevil.example.com) is correctly refused — the policy never sends a request to the dangerous host.Scope / notes
azure-security-confidentialledgerredirect policy.