chore(release): merge release/4.7.1 to main - #2000
Merged
Merged
Conversation
Merges main into develop for the 4.7.0 release.
### Description [ANCHOR-1224](#1965) (fix for [HackerOne #3810399](https://hackerone.com/reports/3810399)) added a mandatory `aud` claim check to `JwtService.decode(..., PlatformAuthJwt.class)`: any token verified against `platformAuthSecret` must now carry `aud=platform_api`, or decoding throws. That PR updated every place inside the Java `core`/`platform` modules that mints or verifies this token type, but missed the one place outside them that also mints it: the Kotlin reference server's `JwtTokenProvider.createJwt`, used by `SepHelper` (via `AuthHeaderUtil.addAuthHeaderIfNeeded`) to sign the reference server's own outgoing calls to the platform's Platform API (`GET /transactions/{id}`, `PATCH /transactions`, and the JSON-RPC endpoint). `createJwt` only ever set `issuedAt`/`expiration` — no `aud` claim at all. So in any deployment where an operator turns on `platform_api.auth.type=jwt` — which they should, since that's what actually closes the vulnerability ANCHOR-1224 patched — every one of the reference server's calls into the platform's Platform API is unconditionally rejected: `JwtService.decode` sees a null audience, throws, and `PlatformAuthJwtFilter`/`AbstractJwtFilter` returns a generic `403 {"error":"forbidden"}`. Two separate logging gaps in the existing code compounded to make this extremely hard to trace back to the actual cause, rather than something wrong with the shared secret itself: - `AbstractJwtFilter.doFilter` catches the exception from `check(...)` and discards it entirely before calling `sendForbiddenError`, so the platform's own logs never show *why* a request was rejected — audience mismatch and a wrong/rotated secret look identical from the outside. - `SepHelper.getTransaction()` never checked the HTTP response status before deserializing the body as a `Transaction`, so the `403`'s `{"error":"forbidden"}` body got fed straight into `Transaction`'s deserializer, producing an unrelated-looking `Illegal input: Fields [id, status, kind] are required...` error instead. That's the error that actually surfaces in the SEP-24 Reference UI's backend and is what made this look like a JWT-secret-mismatch issue on first inspection — it isn't; the shared secret is fine, the token is simply missing a claim the verifier now requires. The end-user symptom: the SEP-24 Reference UI (what wallets are sent to for the interactive deposit/withdraw flow) shows an empty transaction with no form and no action button — the UI's backend can't fetch the transaction record it needs to render, but the underlying cause never made it into any visible error message. **Changes** - [x] `JwtTokenProvider.createJwt` (`kotlin-reference-server`): adds `.audience().add(AUD_PLATFORM_API).and()` before signing, where `AUD_PLATFORM_API = "platform_api"` matches `JwtService.AUD_PLATFORM_API` on the platform side. Only call site is `AuthHeaderUtil.addAuthHeaderIfNeeded`, itself only used for the reference server's calls to the platform's Platform API, so the audience is hardcoded rather than threaded through as a parameter. **Acceptance Criteria** - [x] With `platform_api.auth.type=jwt` set and the reference server's `anchorToPlatformSecret` equal to the platform's `secret.platform_api.auth_secret`, `SepHelper.getTransaction()` (and `patchTransaction`/`rpcAction`) succeed against the platform's Platform API. - [x] A token minted by `JwtTokenProvider.createJwt` before this fix (no `aud` claim) is rejected by `JwtService.decode(..., PlatformAuthJwt.class)` — confirms the regression this fix closes. - [x] The SEP-24 interactive flow, driven end-to-end (SEP-10 → SEP-24 initiate → open interactive URL → reference server's `/start` then `/transaction`), returns the real transaction record instead of `{"error":"forbidden"}` or a deserialization error. ### Context Regression from [ANCHOR-1224](#1965) (fix for [HackerOne #3810399](https://hackerone.com/reports/3810399)). ### Testing - Manual: with `TEST_PROFILE_NAME=auth-jwt-platform` and `RUN_SEP_SERVER=true` (`./gradlew dockerComposeStart && ./gradlew startServersWithTestProfile`), run a SEP-24 withdraw, then reproduce the reference server's own next two calls directly: ```bash curl -X POST http://localhost:8091/start -H "Authorization: Bearer <interactive-url-token>" curl http://localhost:8091/transaction -H "Authorization: Bearer <sessionId-from-/start>" ``` Before this fix: `/transaction` returns `{"msg":"Error occurred: {\"error\": \"forbidden\"}"}`. After: it returns the full transaction JSON (`id`, `status`, `kind`, `amount_expected`, etc.). ### Documentation N/A ### Known limitations N/A [ANCHOR-1224]: https://stellarorg.atlassian.net/browse/ANCHOR-1224?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [ANCHOR-1224]: https://stellarorg.atlassian.net/browse/ANCHOR-1224?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
### Description This bumps the version to 4.7.1 ### Context Release ### Testing `./gradlew test` ### Documentation N/A ### Known limitations N/A
ceciliaromao
approved these changes
Aug 26, 2026
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
Merges release/4.7.1 into main for the 4.7.1 release.
Context
N/A
Testing
./gradlew testDocumentation
N/A
Known limitations
N/A