Skip to content

fix(auth): prevent cross-org account takeover via Okta SSO - #6143

Open
ancorcruz wants to merge 5 commits into
mainfrom
fix/okta-sso-host-account-takeover
Open

ancorcruz wants to merge 5 commits into
mainfrom
fix/okta-sso-host-account-takeover

Conversation

@ancorcruz

@ancorcruz ancorcruz commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Part of INT-203

Context

Okta sign-in resolves the integration from the email domain, then exchanges the authorization code and fetches user identity from the host configured on that integration. The host is admin-configurable, and sign-in just-in-time (JIT) provisioned a membership for whatever email the host returned. An admin of any Okta-enabled organization could therefore point the host at a server they control and receive a session for an unrelated, existing user — a cross-organization account takeover.

Entra ID is unaffected: it fetches identity from a fixed Microsoft Graph endpoint rather than an admin-supplied host.

Changes

  • Cross-org guard (the fix). Reject Okta sign-in when the resolved email belongs to an existing user who is not an active member of the integration's organization. Brand-new users are still provisioned on the fly, and existing members keep signing in — so enabling Okta on an organization with existing members is unaffected. Adding an existing user to another organization now goes through an invite.
  • Case-insensitive userinfo email compare. Okta does not guarantee the casing of the email it returns, so a user whose Okta email differed only in case from the address they typed was wrongly rejected. Aligns with Entra ID.
  • Host format validation (defense-in-depth). The configured host is interpolated into the authorize/token/userinfo URLs, so restrict it to a bare host segment to prevent URL injection / SSRF. Only an explicitly configured host is validated; the derived <organization_name>.okta.com default and custom Okta domains such as login.acme.com remain valid.

If merged before #6146, existing users invited to Okta enabled organizations won't be able to accept the invite and join the organization. I'd still merge it as this fixes a security issue.

## Context

Okta sign-in resolves the integration from the email domain and fetches
the user identity from the integration's admin-configurable host. An
admin of any Okta-enabled organization could point that host at a server
they control and, because login just-in-time provisioned a membership
for the returned email, receive a session for an unrelated existing user
(cross-organization account takeover). Entra ID is unaffected as it
fetches identity from a fixed Microsoft endpoint.

## Description

Reject the sign-in when the resolved email belongs to an existing user
who is not an active member of the integration's organization. Brand-new
users are still provisioned on the fly, and existing members keep signing
in, so enabling Okta on an existing organization is unaffected. Adding an
existing user to another organization must now go through an invite.
## Context

Okta does not guarantee the casing of the email it returns from the
userinfo endpoint, so a user whose Okta email differs only in case from
the address they typed was wrongly rejected with okta_userinfo_error.
Entra ID already compares case-insensitively.

## Description

Match the userinfo email against the expected address with a
case-insensitive comparison, aligning the Okta flow with Entra ID.
## Context

The Okta integration host is admin-configurable and interpolated
directly into the authorize, token and userinfo URLs
(https://<host>/oauth2/v1/...). Without validation an admin could set a
value such as "victim.okta.com@evil.com" or an internal address, sending
the OAuth requests somewhere other than the intended Okta host (URL
injection / SSRF). This mirrors the format validation Entra ID already
enforces.

## Description

Reject a configured host that is not a bare URL host segment
(alphanumerics, dots and hyphens). Only the explicitly configured host is
validated; when none is set the derived <organization_name>.okta.com
default is used and left untouched, so custom Okta domains such as
login.acme.com remain valid. This is defense-in-depth, not the primary
fix for the cross-organization takeover.
@ancorcruz ancorcruz self-assigned this Aug 13, 2026
@ancorcruz
ancorcruz marked this pull request as ready for review August 13, 2026 12:34
@ancorcruz
ancorcruz requested a review from jdenquin August 13, 2026 12:36
Comment thread app/services/auth/okta/login_service.rb Outdated
## Context

The SSO login-method authorization checked whether the user belonged to
any organization with the method enabled, rather than the organization
that configured the integration being used. A user who belonged to one
organization with the method enabled could therefore sign in through a
different organization's integration even when that organization had the
method disabled. This affected both Okta and Entra ID.

## Description

Scope the check to the integration's organization: require the user to be
an active member of that organization and that organization to have the
login method enabled. Raised while reviewing the Okta cross-organization
fix and applied to Entra ID for parity.
@ancorcruz
ancorcruz requested a review from endenis August 14, 2026 12:16
Comment thread app/services/auth/okta/login_service.rb
@ancorcruz
ancorcruz force-pushed the fix/okta-sso-host-account-takeover branch from bf51ecf to b33ad0b Compare August 19, 2026 11:08
## Context

Auth::Okta::AcceptInviteService fetches the user identity from the
integration's admin-configurable host, then accepts the invite through
Invites::AcceptService, which mints a session for the invited email. An
admin could create an invite for an unrelated existing user's email in
their own organization and, using a host they control, accept it to
receive a session as that user - the same cross-organization takeover
already fixed in the login flow. Entra ID is unaffected because it
fetches identity from a fixed Microsoft endpoint.

## Description

Reject the Okta invite acceptance when the invited email belongs to an
existing user who is not already an active member of the invite's
organization, before contacting the host or minting a session. Brand-new
users are still onboarded through the invite; adding an existing user to
another organization must go through an authenticated flow.
@ancorcruz
ancorcruz force-pushed the fix/okta-sso-host-account-takeover branch from b33ad0b to 76177cd Compare August 19, 2026 11:51
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