GHSA-7qjx-gp9h-65qj: Dex Remote Code Execution Vulnerability

HIGH
CVSS 8.7
CWE-285
Published
Advisory Summary

GHSA-7qjx-gp9h-65qj is a HIGH (CVSS 8.7) remote code execution vulnerability (CWE-285: Improper Authorization) affecting Dex libraries in the Go ecosystem. The issue involves token-exchange endpoint is missing allowedconnectors enforcement. Remediation is available by upgrading affected packages to version 0.0.0-20260303131938-204dbb2e3ff7.

GHSA-7qjx-gp9h-65qj at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-7qjx-gp9h-65qj
Severity HIGH
CVSS v3.1 Base Score 8.7
CWE Classification CWE-285: Improper Authorization
Affected Product Dex
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 8.7

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required High (PR:H)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix GHSA-7qjx-gp9h-65qj

To remediate this vulnerability, upgrade all affected Dex dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/dexidp/dex fixed: 0.0.0-20260303131938-204dbb2e3ff7
Upgrade github.com/dexidp/dex to 0.0.0-20260303131938-204dbb2e3ff7
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/dexidp/dex

How to Check if You Are Affected

To determine whether your application is affected by GHSA-7qjx-gp9h-65qj, inspect your project dependencies for Dex:

inspect dependencies for github.com/dexidp/dex

Analyze the terminal output to locate any version of Dex in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.0.0-20260303131938-204dbb2e3ff7), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-285: Improper Authorization, where the product does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action. In Dex, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## 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 exists - `GrantTypeAllowed(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` - calls `isConnectorAllowed`, 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-app` configured with `allowedConnectors: ["dev-google"]` (admin intent: dev-app only sees dev-google identities) - `dev-app`s 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 the `AllowedConnectors` field, `isConnectorAllowed`, `filterConnectors`, and the redirect-flow check sites (`handleConnectorLogin:377`, `parseAuthorizationRequest:535`). Did not modify `handleTokenExchange`. - PR #4619 (commit `7777773`, 2026-03-11, same author, one day earlier) - added `GrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)` to `handleTokenExchange`. 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): 1. **Code-mechanics** - independent cold-read of `server/handlers.go`, `server/oauth2.go`, `storage/storage.go` confirmed the missing check at `handleTokenExchange` and the present checks at the two siblings; cross-checked diffs of PR #4610 (`f80a89d`) and PR #4619 (`7777773`). 2. **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.

GHSA-7qjx-gp9h-65qj Affected Dex Versions

1 component(s)
Fixed Versions:
0.0.0-20260303131938-204dbb2e3ff7
Product / Package Ecosystem Affected Versions Fixed Version
github.com/dexidp/dex
Go
< 0.0.0-20260303131938-204dbb2e3ff7
0.0.0-20260303131938-204dbb2e3ff7

References

Frequently Asked Questions

What is GHSA-7qjx-gp9h-65qj?
GHSA-7qjx-gp9h-65qj is a security vulnerability in Dex involving Token-exchange endpoint is missing AllowedConnectors enforcement under CWE-285: Improper Authorization.
Which Dex versions are affected?
Affected versions include releases prior to 0.0.0-20260303131938-204dbb2e3ff7 across affected packages: github.com/dexidp/dex.
What version fixes GHSA-7qjx-gp9h-65qj?
Upgrading to 0.0.0-20260303131938-204dbb2e3ff7 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/dexidp/dex affected?
Yes, github.com/dexidp/dex is affected in releases prior to 0.0.0-20260303131938-204dbb2e3ff7. Upgrade your dependency to 0.0.0-20260303131938-204dbb2e3ff7 or later.
What is the CVSS score of GHSA-7qjx-gp9h-65qj?
GHSA-7qjx-gp9h-65qj has a CVSS v3.1 base score of 8.7 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N.
What CWE is associated with GHSA-7qjx-gp9h-65qj?
GHSA-7qjx-gp9h-65qj is classified under CWE-285: Improper Authorization (The product does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action.).
How can I check Go dependencies for GHSA-7qjx-gp9h-65qj?
Run the dependency tree command: 'inspect dependencies for github.com/dexidp/dex'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-7qjx-gp9h-65qj",
  "modified" : "2026-06-09T21:59:33Z",
  "published" : "2026-06-09T21:59:33Z",
  "aliases" : [ ],
  "summary" : "Dex: Token-exchange endpoint is missing AllowedConnectors enforcement",
  "details" : "## Summary\n\n`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.\n\n## Affected code path\n\n`handleTokenExchange` reads `connector_id` from the request body at `server/handlers.go:1822`. Validators called between read and token issuance:\n\n- `s.getConnector(ctx, connID)` at line 1836 - confirms connector exists\n- `GrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)` at line 1842 - confirms connector permits this grant\n- **(missing)** `isConnectorAllowed(client.AllowedConnectors, connID)` - never called\n\nTokens are issued at lines 1887 / 1889, bound to `client.ID` carrying claims derived from `connID`.\n\nSibling handlers DO enforce the check:\n\n- `server/handlers.go::handleConnectorLogin:377` - calls `isConnectorAllowed`, returns HTTP 403 \"Connector not allowed for this client.\" (line 380).\n- `server/oauth2.go::parseAuthorizationRequest:535` - same enforcement for the authorization-code flow.\n\nThe doc-string at `storage/storage.go:192-194` reads:\n\n> *AllowedConnectors is a list of connector IDs that the client is allowed to use for authentication. If empty, all connectors are allowed.*\n\nThe phrasing is unconditional - a permission ACL, not a UX filter.\n\n## Impact (concrete scenario)\n\n- Connector `corp-okta` - high-trust, gates production access\n- Connector `dev-google` - low-trust, internal Gmail\n- Client `dev-app` configured with `allowedConnectors: [\"dev-google\"]` (admin intent: dev-app only sees dev-google identities)\n- `dev-app`s client secret leaks (CI artifact, env file, breached service-account secret store)\n\nWithout 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.\n\nWith the bug, an attacker holding their own legitimate `corp-okta` ID token sends:\n\n```\nPOST /token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=urn:ietf:params:oauth:grant-type:token-exchange\n&client_id=dev-app\n&client_secret=<leaked>\n&connector_id=corp-okta\n&subject_token=<attackers own corp-okta id token>\n&subject_token_type=urn:ietf:params:oauth:token-type:id_token\n&scope=openid+groups\n```\n\nDex 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.\n\n## Severity (self-assessed)\n\nCVSS 3.1 vector: `AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N` -> **8.7 HIGH**.\n\nThe `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.\n\n## Affected version\n\n`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.\n\n## Precedent / lineage\n\n- PR #4610 (commit `f80a89d`, 2026-03-11) - added the `AllowedConnectors` field, `isConnectorAllowed`, `filterConnectors`, and the redirect-flow check sites (`handleConnectorLogin:377`, `parseAuthorizationRequest:535`). Did not modify `handleTokenExchange`.\n- PR #4619 (commit `7777773`, 2026-03-11, same author, one day earlier) - added `GrantTypeAllowed(conn.GrantTypes, grantTypeTokenExchange)` to `handleTokenExchange`. Added a connector-side grant-type gate but did not add the symmetric client-side connector ACL.\n\n## Suggested fix\n\nInsert `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.\n\n## Verification methodology\n\nTwo-stage verification per IRIS / XBOW pattern (LLM-assisted research with non-LLM verifier as last stage):\n\n1. **Code-mechanics** - independent cold-read of `server/handlers.go`, `server/oauth2.go`, `storage/storage.go` confirmed the missing check at `handleTokenExchange` and the present checks at the two siblings; cross-checked diffs of PR #4610 (`f80a89d`) and PR #4619 (`7777773`).\n2. **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.\n\n`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.\n\n## Reporter\n\nMatteo Panzeri (GitHub: @matte1782, contact: matteo1782@gmail.com). Please credit as **Matteo Panzeri** if a CVE is requested.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/dexidp/dex"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.0.0-20260303131938-204dbb2e3ff7"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/dexidp/dex/security/advisories/GHSA-7qjx-gp9h-65qj"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/dexidp/dex/commit/204dbb2e3ff7692af3b7ca4362b1ee46fb43c227"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/dexidp/dex"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-285" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-09T21:59:33Z",
    "nvd_published_at" : null
  }
}