fix(server): enforce client.AllowedConnectors in handleTokenExchange (GHSA-7qjx-gp9h-65qj)#4784
Merged
nabokihms merged 1 commit intoMay 11, 2026
Conversation
The token-exchange grant did not check client.AllowedConnectors before invoking the connector, while handleConnectorLogin (handlers.go:377) and parseAuthorizationRequest (oauth2.go:535) both call isConnectorAllowed. This left a confidential client able to exchange a subject token via a connector not in its AllowedConnectors list, provided the connector existed in the dex configuration and supported the token-exchange grant. Insert isConnectorAllowed before getConnector in handleTokenExchange so a disallowed request cannot probe connector existence. Mirrors the placement and error shape of the two existing call sites. Tests: TestHandleTokenExchangeAllowedConnectors covers allowed, allowed-non-first-entry, denied, and empty (permit-any) cases. Addresses GHSA-7qjx-gp9h-65qj. Signed-off-by: Matteo Panzeri <matteo1782@gmail.com>
cardoe
reviewed
May 11, 2026
Contributor
cardoe
left a comment
There was a problem hiding this comment.
This makes sense to me. +1
kanywst
added a commit
to kanywst/dex
that referenced
this pull request
May 13, 2026
Resolve a conflict in server/handlers.go between dexidp#4784, which enforces client.AllowedConnectors in handleTokenExchange, and the ID-JAG token exchange branch. The AllowedConnectors check now runs before the ID-JAG dispatch so the per-client connector allowlist applies to both standard and ID-JAG token exchanges. Signed-off-by: kanywst <niwatakuma@icloud.com>
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.
Overview
Adds enforcement of
client.AllowedConnectorsinhandleTokenExchange. Two sibling code paths already enforce this client policy; the token exchange path was missing it.Addresses GHSA-7qjx-gp9h-65qj. Only master is affected.
What this PR does / why we need it
The asymmetry before this PR:
server/handlers.go::handleConnectorLoginline 377 callsisConnectorAllowed(client.AllowedConnectors, connID)beforegetConnectorand returns 403 on deny.server/oauth2.go::parseAuthorizationRequestline 535 calls the same helper and returns a redirectederrInvalidRequeston deny.server/handlers.go::handleTokenExchangedid not call it. A confidential client withAllowedConnectors: ["okta"]could exchange a subject token viaconnector_id=ldapprovided that LDAP connector existed in the dex configuration and supported the token-exchange grant type.The change inserts one call to
isConnectorAllowedinhandleTokenExchangebetween the existingsubjectTokenempty check andgetConnector. Placement mirrorshandleConnectorLogin:377andoauth2.go:535(check runs before the connector fetch) so a disallowed request cannot probe connector existence. Error shape mirrors sibling token-endpoint errors in the same function:tokenErrHelper(errInvalidRequest, "Connector not allowed for this client.", http.StatusBadRequest). Log message and field shape mirrorhandleConnectorLogin:378-379exactly.Tests added under
TestHandleTokenExchangeAllowedConnectorscover four cases: allowed (single entry), allowed (non-first entry in a multi-entry list), denied, and empty list (existing permit-any semantic). Structure mirrorsTestHandleTokenExchangeConnectorGrantTypeRestriction.go test ./server/...passes for the diff. One unrelated pre-existing flake inTestOAuth2DeviceFlow/verify_id_token_and_oauth2_token_expiry#01reproduces on stock master at the same commit (token-expiry timing assertion drifting under containerized scheduling) and is not introduced by this PR.Special notes for your reviewer
ca3d56763f168bd6faee3e7701c43fd379d813d8.handleTokenExchange. The two PRs do not overlap (a grep of the feat(oauth2): implement Identity Assertion JWT (ID-JAG) issuance (DEP #4600) #4611 diff forAllowedConnectorsandisConnectorAllowedreturns zero hits); if feat(oauth2): implement Identity Assertion JWT (ID-JAG) issuance (DEP #4600) #4611 lands first I will rebase and re-test.