Repository navigation
[ANCHOR-1400]: Validate the SEP-45 home domain with the shared matcher and restrict wildcard matching - #2087
Merged
Merged
Conversation
…matcher on validate
…the verification found in the tests
…empty or hyphen-edged label
… SEP-10 challenge request
…SEP-10 challenge validation
… and host length limits
…P-10 challenge request
…P-45 challenge and validation
amandagonsalves
approved these changes
Nov 12, 2026
…ts and pin the SEP-10 PoC (#2088) ### Description - Rejects a wildcard `home_domains` match whose host has a label longer than 63 characters or is longer than 253 characters (the `:port` is not counted). The check lives in `ClientDomainHelper.hasValidHostLabels`, so SEP-10 and SEP-45 both get it. Exactly 63 and exactly 253 are still accepted. The exact-match branch is unchanged. - Adds regression tests for report #4108627 at the three SEP-10 call sites of the matcher, using the reporter's fixture (`*.wildcard.stellar.org`) and strings: `evil.com/x.wildcard.stellar.org` and `a.wildcard.stellar.org/evil` are rejected, `abc.def.wildcard.stellar.org` and `a.wildcard.stellar.org` are accepted. - `createChallenge` (GET `/auth`) - `validateChallenge` (POST `/auth`, operation key name check) - `validateChallengeTransactionHomeDomain` ### Context - Report #[4108627](https://hackerone.com/reports/4108627): SEP-10 signed a caller-chosen `home_domain` on a wildcard config because `isDomainNameMatch` expanded `*` to `.*`, so `evil.com/x.wildcard.stellar.org` matched `*.wildcard.stellar.org`. - The fix for that claim (`*` limited to `[A-Za-z0-9_.-]`, plus empty/hyphen-edged label rejection) is already in #2087 (ANCHOR-1400), which this branch is stacked on. This PR does not touch it. - What was left: (1) only `createChallenge` had a test with a slash payload, and with another fixture; the POST `/auth` sites had none. (2) The assessment promised to reject a `home_domain` that is not a syntactically valid host, but a label over 63 characters or a host over 253 still matched under `*.sdp.stellar.org`, which no DNS host can have. ### Testing - `./gradlew test` - `./gradlew :core:test` passes in full (1168 tests); 14 tests added in `ClientDomainHelperTest` (7), `Sep10ServiceTest` (6) and `Sep45ServiceTest` (1). - Length limits are tested at the limit and at limit+1 (63/64 label, 253/254 host, with and without a `:8080` port pattern). - `./gradlew :core:spotlessCheck` passes. - Independent verification: all 15 spec checks pass at HEAD; 3 mutations (`>` to `>=` on each limit, dropping the port strip) and 15 more throwaway ones (including `*` back to `.*`) were all caught by the tests. ### Documentation N/A: internal validation change, no feature or public API change. ### Known limitations - Stacked on #2087 (`fix/anchor-1400`): retarget this PR to `develop` once #2087 merges. - The length limits apply only to wildcard matches. A configured exact domain is compared by equality with no length rule, because that text comes from operator config, not from the request. - `_` is still accepted in wildcard labels (kept on purpose in ANCHOR-1400). - The reporter's PoC is covered at unit level only; there is no integration test through the running `/auth` endpoints.
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
home_domainwith the same matcher SEP-10 uses (ClientDomainHelper.isDomainNameMatch), in bothgetChallengeandvalidate, instead of comparing onlyURI.getAuthority(). A value that differs from a configured domain by a path, query, fragment, userinfo or backslash is rejected with400 Invalid home domain.getChallengeruns the check before it creates the nonce, simulates the transaction or fetches theclient_domain, so nothing is built or server-signed for a rejected value.http://orhttps://removed), so clients that send a scheme or mixed case keep working. The SEP-45 JWT now carries the normalized domain (localhost:8080) inissandhome_domain; the challenge still echoes the value the client sent.*inhome_domainsnow matches only letters, digits,-,_and.(it used to be.*). This fixes wildcards never matching a real subdomain in SEP-45, and stops*.example.orgfrom matching values likeevil.example/x.example.orgin SEP-45 and SEP-10.validaterejects an empty (or scheme-only)home_domainand a missing one with400 Invalid home domain(a missing one used to be an NPE).Context
Sep45Serviceaccepted and signed ahome_domainthat SEP-10 rejects, andWebAuthJwtFilteraccepts that token on the SEP-24 endpoints, where the home domain is copied into the interactive-URL token..*wildcard also let/ ? # @through, so the wildcard is tightened in the shared helper as part of the same change.Testing
./gradlew test./gradlew :core:test:Sep45ServiceTest(27),ClientDomainHelperTest(29),Sep10ServiceTest(73), 0 failures. New tests cover each rejected value, the wildcard accept/reject cases, scheme and case tolerance, the signed claims, and that a rejected challenge creates no nonce and runs no simulation../gradlew :core:spotlessCheck :essential-tests:spotlessCheck./gradlew :essential-tests:testSep45(6) and:essential-tests:testSep10(21 cases) against the local stack: 0 failures.Sep45Testsnow expects the bare domain injwt.issandjwt.homeDomain.Documentation
N/A. No new configuration or API; the
home_domainscomment inanchor-config-default-values.yamlalready describes the wildcard form.Known limitations
issandhome_domainchange from the value the client sent (e.g.http://localhost:8080) to the normalized domain (localhost:8080). Relying parties comparing against the scheme-prefixed form need to match on the bare domain..example.org) still matches*.example.org, as before, because*can match the empty string.Sep24End2EndTests(SEP-45 wallet flow over Kafka events) was not run locally.