GHSA-7qjx-gp9h-65qj
Dex: Token-exchange endpoint is missing AllowedConnectors enforcement
GHSA-7qjx-gp9h-65qj is a high vulnerability (CVSS 8.7) in github.com/dexidp/dex, published June 9, 2026. No source lists public exploit code. Fixed in github.com/dexidp/dex 0.0.0-20260303131938-204dbb2e3ff7.
- Severity
- 8.7 HighCVSS 3.1, GitHub Advisories
- Exploit chance
- UnscoredNo EPSS score yet
- Exploitation
- None knownNot on CISA’s or ENISA’s lists
- Fixed in
0.0.0-20260303131938-204dbb2e3ff7github.com/dexidp/dex
Description
Summary
server/handlers.go::handleTokenExchange (lines 1804-1893) does not call isConnectorAllowed(client.AllowedConnectors, connID) before issuing tokens, while sibling handlers do. This is a per-client connector ACL gap on the token-exchange endpoint; the redirect-flow paths enforce the same field correctly.
Affected code path
handleTokenExchange reads connector_id from the request body at server/handlers.go:1822. Validators called between read and token issuance:
s.getConnector(ctx, connID)at line 1836 - confirms connector existsGrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)at line 1842 - confirms connector permits this grant- (missing)
isConnectorAllowed(client.AllowedConnectors, connID)- never called
Tokens are issued at lines 1887 / 1889, bound to client.ID carrying claims derived from connID.
Sibling handlers DO enforce the check:
server/handlers.go::handleConnectorLogin:377- callsisConnectorAllowed, returns HTTP 403 "Connector not allowed for this client." (line 380).server/oauth2.go::parseAuthorizationRequest:535- same enforcement for the authorization-code flow.
The doc-string at storage/storage.go:192-194 reads:
AllowedConnectors is a list of connector IDs that the client is allowed to use for authentication. If empty, all connectors are allowed.
The phrasing is unconditional - a permission ACL, not a UX filter.
Impact (concrete scenario)
- Connector
corp-okta- high-trust, gates production access - Connector
dev-google- low-trust, internal Gmail - Client
dev-appconfigured withallowedConnectors: ["dev-google"](admin intent: dev-app only sees dev-google identities) dev-apps client secret leaks (CI artifact, env file, breached service-account secret store)
Without the bug, the leaked secret would only allow the attacker to mint tokens via dev-google - blast radius bounded by what any dev-google user can already do.
With the bug, an attacker holding their own legitimate corp-okta ID token sends:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&client_id=dev-app
&client_secret=<leaked>
&connector_id=corp-okta
&subject_token=<attackers own corp-okta id token>
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
&scope=openid+groups
Dex returns an ID token signed by Dex, aud=dev-app, carrying the attackers corp-okta groups. Downstream services trusting tokens issued for dev-app see the attacker as a corp-okta user - a combination the admins policy explicitly forbade.
Severity (self-assessed)
CVSS 3.1 vector: AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N -> 8.7 HIGH.
The PR:H precondition is a real reduction (requires leaked confidential client_secret PLUS attacker holding a subject_token from a forbidden connector that has token-exchange enabled). Defer to your scoring - HIGH and MEDIUM are both defensible.
Affected version
master only - not yet in any released tag. Latest release v2.45.1 (2026-03-03) predates PR #4610 (commit f80a89d, 2026-03-11) which introduced AllowedConnectors. Production deployments on stable releases are NOT affected; deployments pulling from master / nightly images are. A fix can be merged ahead of the next release without an embargo for past versions.
Precedent / lineage
- PR #4610 (commit
f80a89d, 2026-03-11) - added theAllowedConnectorsfield,isConnectorAllowed,filterConnectors, and the redirect-flow check sites (handleConnectorLogin:377,parseAuthorizationRequest:535). Did not modifyhandleTokenExchange. - PR #4619 (commit
7777773, 2026-03-11, same author, one day earlier) - addedGrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)tohandleTokenExchange. Added a connector-side grant-type gate but did not add the symmetric client-side connector ACL.
Suggested fix
Insert isConnectorAllowed(client.AllowedConnectors, connID) between the existing getConnector / GrantTypeAllowed checks and the connector cast at line 1847, returning HTTP 403 via the token-endpoint error helper. Mirror the existing patterns at handlers.go:377-380 and oauth2.go:535. One-block addition.
Verification methodology
Two-stage verification per IRIS / XBOW pattern (LLM-assisted research with non-LLM verifier as last stage):
- Code-mechanics - independent cold-read of
server/handlers.go,server/oauth2.go,storage/storage.goconfirmed the missing check athandleTokenExchangeand the present checks at the two siblings; cross-checked diffs of PR #4610 (f80a89d) and PR #4619 (7777773). - External grounding - cross-checked
docs/configuration/customization,docs/guides/token-exchange/, RFC 8693 (which defers per-client policy to implementations),.github/SECURITY.md, GHSA dashboard, huntr.com, and existing issues including #3546 (different mechanism: connector-level disable list, orthogonal to this finding). No prior public report of this gap was found.
semgrep (p/golang + p/security-audit) on server/ returned no ERROR-severity findings - the static tool cannot detect missing-validator gaps; evidence rests on file:line grep + sibling-handler comparison above.
Reporter
Matteo Panzeri (GitHub: @matte1782, contact: matteo1782@gmail.com). Please credit as Matteo Panzeri if a CVE is requested.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- High
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- None
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/dexidp/dexGo | before 0.0.0-20260303131938-204dbb2e3ff7 | 0.0.0-20260303131938-204dbb2e3ff7 |
What each source reports
GitHub Advisories Score used 8.7
Dex: Token-exchange endpoint is missing AllowedConnectors enforcement
Summary
server/handlers.go::handleTokenExchange (lines 1804-1893) does not call isConnectorAllowed(client.AllowedConnectors, connID) before issuing tokens, while sibling handlers do. This is a per-client connector ACL gap on the token-exchange endpoint; the redirect-flow paths enforce the same field correctly.
Affected code path
handleTokenExchange reads connector_id from the request body at server/handlers.go:1822. Validators called between read and token issuance:
s.getConnector(ctx, connID)at line 1836 - confirms connector existsGrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)at line 1842 - confirms connector permits this grant- (missing)
isConnectorAllowed(client.AllowedConnectors, connID)- never called
Tokens are issued at lines 1887 / 1889, bound to client.ID carrying claims derived from connID.
Sibling handlers DO enforce the check:
server/handlers.go::handleConnectorLogin:377- callsisConnectorAllowed, returns HTTP 403 "Connector not allowed for this client." (line 380).server/oauth2.go::parseAuthorizationRequest:535- same enforcement for the authorization-code flow.
The doc-string at storage/storage.go:192-194 reads:
AllowedConnectors is a list of connector IDs that the client is allowed to use for authentication. If empty, all connectors are allowed.
The phrasing is unconditional - a permission ACL, not a UX filter.
Impact (concrete scenario)
- Connector
corp-okta- high-trust, gates production access - Connector
dev-google- low-trust, internal Gmail - Client
dev-appconfigured withallowedConnectors: ["dev-google"](admin intent: dev-app only sees dev-google identities) dev-apps client secret leaks (CI artifact, env file, breached service-account secret store)
Without the bug, the leaked secret would only allow the attacker to mint tokens via dev-google - blast radius bounded by what any dev-google user can already do.
With the bug, an attacker holding their own legitimate corp-okta ID token sends:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&client_id=dev-app
&client_secret=<leaked>
&connector_id=corp-okta
&subject_token=<attackers own corp-okta id token>
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
&scope=openid+groups
Dex returns an ID token signed by Dex, aud=dev-app, carrying the attackers corp-okta groups. Downstream services trusting tokens issued for dev-app see the attacker as a corp-okta user - a combination the admins policy explicitly forbade.
Severity (self-assessed)
CVSS 3.1 vector: AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N -> 8.7 HIGH.
The PR:H precondition is a real reduction (requires leaked confidential client_secret PLUS attacker holding a subject_token from a forbidden connector that has token-exchange enabled). Defer to your scoring - HIGH and MEDIUM are both defensible.
Affected version
master only - not yet in any released tag. Latest release v2.45.1 (2026-03-03) predates PR #4610 (commit f80a89d, 2026-03-11) which introduced AllowedConnectors. Production deployments on stable releases are NOT affected; deployments pulling from master / nightly images are. A fix can be merged ahead of the next release without an embargo for past versions.
Precedent / lineage
- PR #4610 (commit
f80a89d, 2026-03-11) - added theAllowedConnectorsfield,isConnectorAllowed,filterConnectors, and the redirect-flow check sites (handleConnectorLogin:377,parseAuthorizationRequest:535). Did not modifyhandleTokenExchange. - PR #4619 (commit
7777773, 2026-03-11, same author, one day earlier) - addedGrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)tohandleTokenExchange. Added a connector-side grant-type gate but did not add the symmetric client-side connector ACL.
Suggested fix
Insert isConnectorAllowed(client.AllowedConnectors, connID)…
- Record
GHSA-7qjx-gp9h-65qj- CVSS 3.1
- 8.7 High
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-285
- Updated
- 2026-11-02
OSV 8.7
Dex: Token-exchange endpoint is missing AllowedConnectors enforcement
Summary
server/handlers.go::handleTokenExchange (lines 1804-1893) does not call isConnectorAllowed(client.AllowedConnectors, connID) before issuing tokens, while sibling handlers do. This is a per-client connector ACL gap on the token-exchange endpoint; the redirect-flow paths enforce the same field correctly.
Affected code path
handleTokenExchange reads connector_id from the request body at server/handlers.go:1822. Validators called between read and token issuance:
s.getConnector(ctx, connID)at line 1836 - confirms connector existsGrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)at line 1842 - confirms connector permits this grant- (missing)
isConnectorAllowed(client.AllowedConnectors, connID)- never called
Tokens are issued at lines 1887 / 1889, bound to client.ID carrying claims derived from connID.
Sibling handlers DO enforce the check:
server/handlers.go::handleConnectorLogin:377- callsisConnectorAllowed, returns HTTP 403 "Connector not allowed for this client." (line 380).server/oauth2.go::parseAuthorizationRequest:535- same enforcement for the authorization-code flow.
The doc-string at storage/storage.go:192-194 reads:
AllowedConnectors is a list of connector IDs that the client is allowed to use for authentication. If empty, all connectors are allowed.
The phrasing is unconditional - a permission ACL, not a UX filter.
Impact (concrete scenario)
- Connector
corp-okta- high-trust, gates production access - Connector
dev-google- low-trust, internal Gmail - Client
dev-appconfigured withallowedConnectors: ["dev-google"](admin intent: dev-app only sees dev-google identities) dev-apps client secret leaks (CI artifact, env file, breached service-account secret store)
Without the bug, the leaked secret would only allow the attacker to mint tokens via dev-google - blast radius bounded by what any dev-google user can already do.
With the bug, an attacker holding their own legitimate corp-okta ID token sends:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&client_id=dev-app
&client_secret=<leaked>
&connector_id=corp-okta
&subject_token=<attackers own corp-okta id token>
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
&scope=openid+groups
Dex returns an ID token signed by Dex, aud=dev-app, carrying the attackers corp-okta groups. Downstream services trusting tokens issued for dev-app see the attacker as a corp-okta user - a combination the admins policy explicitly forbade.
Severity (self-assessed)
CVSS 3.1 vector: AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N -> 8.7 HIGH.
The PR:H precondition is a real reduction (requires leaked confidential client_secret PLUS attacker holding a subject_token from a forbidden connector that has token-exchange enabled). Defer to your scoring - HIGH and MEDIUM are both defensible.
Affected version
master only - not yet in any released tag. Latest release v2.45.1 (2026-03-03) predates PR #4610 (commit f80a89d, 2026-03-11) which introduced AllowedConnectors. Production deployments on stable releases are NOT affected; deployments pulling from master / nightly images are. A fix can be merged ahead of the next release without an embargo for past versions.
Precedent / lineage
- PR #4610 (commit
f80a89d, 2026-03-11) - added theAllowedConnectorsfield,isConnectorAllowed,filterConnectors, and the redirect-flow check sites (handleConnectorLogin:377,parseAuthorizationRequest:535). Did not modifyhandleTokenExchange. - PR #4619 (commit
7777773, 2026-03-11, same author, one day earlier) - addedGrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)tohandleTokenExchange. Added a connector-side grant-type gate but did not add the symmetric client-side connector ACL.
Suggested fix
Insert isConnectorAllowed(client.AllowedConnectors, connID)…
- Record
GHSA-7qjx-gp9h-65qj- CVSS 3.1
- 8.7 High
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-285
- Updated
- 2026-11-02
OSVGO-2026-5231No score
Dex: Token-exchange endpoint is missing AllowedConnectors enforcement in github.com/dexidp/dex
Dex: Token-exchange endpoint is missing AllowedConnectors enforcement in github.com/dexidp/dex
- Record
GO-2026-5231- Updated
- 2026-11-02
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | GitHub Advisories, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
References
Left out here: the rest of 2 source descriptions. The JSON record has them.