Skip to content

[ANCHOR-1405]: Resolve db-mode client lookups by client type - #2090

Merged
ceciliaromao merged 5 commits into
developfrom
fix/anchor-1405
Nov 13, 2026
Merged

ceciliaromao merged 5 commits into
developfrom
fix/anchor-1405

Conversation

@ceciliaromao

Copy link
Copy Markdown
Collaborator

Description

  • JdbcClientService.getClientConfigBySigningKey now returns a client only when the row found is CUSTODIAL, and getClientConfigByDomain only when it is NONCUSTODIAL. A row of the other type resolves to null, as in the json store (DefaultClientService).
  • The repo queries, ClientConfigService and the migrations are unchanged. getClientConfigByDomainAndAccount composes the two lookups and inherits the fix.
  • Behavior change: in db mode, a non-custodial client that carries a signing key (or a custodial client that carries a domain) no longer resolves through that field. This can change client_name attribution and the custodial destination gate for such rows. Release note needed.

Context

  • HackerOne #4108778. In db client-store mode both lookups wrapped whatever row findBySigningKey / findByDomain returned, with no type check, while toClientConfig and getCustodialClients() already filter by type. ClientConfigService.validate does not stop a non-custodial client from carrying signing keys, destination accounts and allow_any_destination.
  • Consequence 1: ClientFinder attributed a caller to a non-custodial client's client_name from a bare SEP-10 account matching its signing key, without domain proof.
  • Consequence 2: SepRequestValidator.validateDestinationAccount opened the custodial-only destination gate from a non-custodial row.
  • The fix routes both lookups through the type check the class already has, so db mode matches json mode. ANCHOR-1405.

Testing

  • ./gradlew test
  • ./gradlew :platform:test --tests '*JdbcClientServiceTest*' --tests '*JdbcClientServiceConsumersTest*': the reporter's row (noncustodial, signing key, allowAnyDestination=true) resolves to null by key, gets no client_name from a bare-account token (optional and required attribution), and does not open the destination gate; custodial rows map as before; reclassifying a row flips both lookups on the next call.
  • The new consumer tests fail against the pre-fix JdbcClientService (4 of 5; the fifth is the custodial control).
  • ./gradlew spotlessCheck
  • e2e, ClientsDb suite (ClientsDbAttributionTests, new case: a non-custodial client with a domain and a signing key gets no client_name from a SEP-10 token for that key). Run locally on the db-mode stack: 6 tests, 0 failures.
  • Independent review: 3 mutations of the type checks, all killed.

Documentation

N/A (no feature or public API change).

Known limitations

  • Not changed on purpose: ClientConfigService.upsert / addSigningKey still accept a non-custodial client with signing keys and a custodial client with domains. A write-time exclusivity guard would be an API-contract change that can reject configs accepted today.
  • Existing mixed rows are not migrated; they stop resolving through the wrong field.

@ceciliaromao ceciliaromao self-assigned this Oct 31, 2026
@ceciliaromao
ceciliaromao merged commit ff5fd5d into develop Nov 13, 2026
35 of 38 checks passed
@ceciliaromao
ceciliaromao deleted the fix/anchor-1405 branch November 13, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants