Skip to content

Validate that the "/web/sso_confirm" redirect URL is only used for MFA ceremonies #56006

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

Joerger
Copy link
Contributor

@Joerger Joerger commented Jun 23, 2025

Follow up to #55398

This change does not have any known security impact, but it adds some better partitioning between SSO ceremony types to ensure that using the Web MFA specific redirect URL "/web/sso_confirm" can not even be attempted outside of MFA flows.

I also moved the function out of lib/auth/github.go to lib/client/sso/redirector.go since it is not github specific, and updated the comment for readability.

…so/redirector.go

* Replace binary ssoTestFlow boolean with ceremony type to incorporate MFA ceremonies

* Validate that "/web/sso_confirm" is only used for MFA ceremonies
@Joerger Joerger requested a review from rosstimothy June 23, 2025 18:29
@Joerger Joerger added the no-changelog Indicates that a PR does not require a changelog entry label Jun 23, 2025
@github-actions github-actions bot requested review from hugoShaka and vapopov June 23, 2025 18:29
Copy link
Collaborator

@zmb3 zmb3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also move the tests to redirector_test.go?

@Joerger Joerger requested a review from zmb3 June 23, 2025 19:03
// For non test ceremonies, If the "insecure_allowed_cidr_ranges" list is non-empty, URLs in both the
// "http" and "https" schema are allowed if the hostname is an IP address that is contained in a
// specified CIDR range on any port.
func ValidateClientRedirect(clientRedirect string, ceremonyType CeremonyType, settings *types.SSOClientRedirectSettings) error {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a security-critical function. Can we add more comments (maybe inside the body of the function) to warn future devs that this function is our main protection against open redirect vulnerabilities?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, adding this comment at the top of the function:

// Warning to developers and reviewers: this validation function is critical to sso security
// and any changes to it should be carefully considered from a vulnerability point of view.

}
if q, err := url.ParseQuery(u.RawQuery); err != nil {
return trace.Wrap(err, "parsing query in client redirect URL")
} else if len(q) != 1 || len(q["secret_key"]) != 1 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct that the secret_key query parameter doesn't need to be validated for SSO MFA?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the secret_key is not used for the web SSO MFA flow. For non web SSO flows, the secret_key is required on the server side to encode the response:

teleport/lib/web/apiserver.go

Lines 2333 to 2348 in e71690a

if u.Path == sso.WebMFARedirect {
// Transform the web sso mfa redirectURL into a relative redirect, preserving
// query parameters while ignoring scheme, hostname, and other url parts.
q := u.Query()
q.Add("response", string(out))
return &url.URL{
Path: sso.WebMFARedirect,
RawQuery: q.Encode(),
}, nil
}
// Extract secret out of the request.
secretKey := u.Query().Get("secret_key")
if secretKey == "" {
return nil, trace.BadParameter("missing secret_key")
}

If a non-web client tried to abuse this by setting the path to /web/sso_confirm and not setting a secret_key, it would fail thanks to the previous fix enforcing the use of a relative URL on the server side.

return trace.BadParameter("the web mfa redirect path, \"/web/sso_confirm\", cannot be used for non-MFA flows")
}
if u.IsAbs() {
return trace.BadParameter("invalid scheme in client redirect URL for SSO MFA")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return trace.BadParameter("invalid scheme in client redirect URL for SSO MFA")
return trace.BadParameter("redirects for SSO MFA must be relative")

Or something similar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like I failed to address this comment, taking that suggestion instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-changelog Indicates that a PR does not require a changelog entry size/sm
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants