Summary
On October 3, 2022, Dex, the federated identity provider that Sigstore uses to issue identity tokens, published CVE-2022-39222 with a GitHub Security Advisory. Sigstore was vulnerable to this CVE, but we were able to quickly mitigate the vulnerability in June before an official fix was published.
Details
On June 13, 2022, Joern Schneeweisz from the GitLab Security Research Team disclosed a vulnerability to Sigstore where an attacker executing a phishing campaign against a user can acquire a user’s identity token through a backchannel. Upon further investigation, we determined that the vulnerability was in Dex, the federated identity provider that Sigstore uses to issue identity tokens.
At a high level, when a user requests an identity token for Sigstore, Dex federates the authentication to a third-party connector such as Google, Microsoft or GitHub. After verifying the identity token from the connector, Dex constructs an identity token for Sigstore.
As part of the OAuth/OpenID Connect (OIDC) authorization flow, Dex constructs a code that can be exchanged for an identity token. Dex also provides an API method to fetch a generated OAuth code given a request ID. The request ID comes from a certain parameter, state
, on the request to the federated identity provider. A typical life of a request is as follows:
- A user is directed to
oauth2.sigstore.dev/auth
to select a federated connector. This will include a callback URI so that Dex can redirect the user back to the client that requested the login. - A user selects a federated connector, such as
accounts.google.com
. - Dex constructs a redirect to the federated connector. This includes a callback URI so that the federated connector redirects back to Dex, and a
state
parameter that is persisted by Dex. - The user is redirected to the federated connector, and authenticates. The connector redirects the user back to the callback URI. The redirect will include the
state
parameter and a newcode
parameter. - Dex handles the callback, exchanging the
code
for the user’s identity token from the federated connector, persisting the claims of the token. Dex generates an OAuth code. Then Dex redirects the browser to a Dex/approval
endpoint with thestate
request ID. - Dex uses the request ID to look up the OAuth code, and builds a redirect to the original callback with the
code
. - The client will then call Dex to exchange the
code
for a Sigstore identity token.
The vulnerability was due to a predictable request ID. An attacker that initiates a login request to Dex could intercept the state
parameter and attempt to request a code from /approval
before the user can. The phishing attack is as follows:
- A victim navigates to a malicious website.
- The malicious webserver initiates a connection with a Dex instance directly for a specific federated connector —
https://oauth2.sigstore.dev/auth/auth/https://accounts.google.com?access_type=online&client_id=sigstore&nonce=1AaJAimQU9CbeOFsNra1d7CJTWB&redirect_uri=http://localhost:40393/auth/callback&response_type=code&scope=openid+email&state=1AaJAjhpUmsB25csCo5muvorMTl
- Dex returns a 302 Redirect to the federated connector —
https://accounts.google.com/o/oauth2/v2/auth?client_id=237800849078-hri2ndt7gdafpf34kq8crd5sik9pe3so.apps.googleusercontent.com&redirect_uri=https://oauth2.sigstore.dev/auth/callback&response_type=code&scope=openid+email&state=
g3dkmpontsr4ugocoddjx72ef
. The attacker records thestate
parameter valueg3dkmpontsr4ugocoddjx72ef
which will be used as the request ID later on. - The malicious website redirects the victim’s browser to the federated connector.
- The user authenticates to the connector. If they have authenticated before, they may not be presented with an authentication challenge.
- While the user goes through the authentication flow with the connector, the malicious webserver will repeatedly request
/approval?req=
g3dkmpontsr4ugocoddjx72ef
. Once the user has successfully authenticated, if the webserver is able to call/approval
before the victim’s browser calls/approval
, then an attacker can fetch the Dex OAuth code which can be exchanged for an identity token.
Response and Fix
On June 14, Sigstore maintainers reached out to Dex maintainers to report the vulnerability. Dex acknowledged the vulnerability, created a draft GitHub Security Advisory, and Sigstore and Dex collaborated on a patch to fix the vulnerability. The vulnerability was assigned CVE-2022-39222 (GitHub Security Advisory), and Dex published a fix for the vulnerability on October 3, 2022.
Sigstore maintains a private fork of the Dex repository to quickly patch bugs or customize behavior. This allowed Sigstore maintainers to quickly patch the vulnerability and roll out a fix by June 14.
To mitigate this vulnerability, we added message authentication to the /approval
endpoint in the form of an HMAC. To construct an HMAC, a secret value is concatenated with a message before being hashed. It is cryptographically impossible to reverse the hash, nor is it possible to construct the HMAC without the secret value. The /approval
endpoint will require that an HMAC be presented along with the request ID. The only way to get the HMAC is through the redirect from the federated connector to Dex (/callback
), and the attacker cannot intercept this redirect. Requests from an attacker repeatedly requesting the /approval
endpoint will be rejected.