Currently accepting new security engagementsRequest a scope
Redacted engagementCriticalOAuth and single sign-on misconfiguration

OAuth misconfiguration that allowed one account to be linked to another

Single sign-on was configured so that the identity returned by the provider was trusted more than the account it was being attached to. The result was an account linking path that let one identity end up in control of a different user's account. This is the class of issue that reads as a configuration detail and behaves as a full account takeover.

A SaaS platform offering social sign-in alongside email and password login

Redacted. This describes work that was carried out. The client, the product, the affected endpoints and the exact requests are deliberately absent, and no detail here would help anyone locate or reproduce the issue on the original system. Published with the class and the reasoning intact because that is the part you can act on.

The situation

The platform had added social login after the fact, on top of an existing email and password system. Both paths could reach the same account. Testing focused on what happens at the join between them, because that join is where two sets of assumptions meet and neither side owns the result.

How it was approached

  1. Mapped every route into an authenticated session: password login, social sign-in, invitation acceptance and password reset.
  2. Registered controlled accounts on both sides of the join and watched how identifiers were carried between the provider and the application.
  3. Tested the authorization response for the checks that matter: whether state was bound to the session that started the flow, whether the redirect target was constrained to an allow list, and whether the returned identity was verified before it was trusted.
  4. Tested account linking specifically, including linking while unauthenticated, linking to an address that already existed, and linking an address the provider had not confirmed.

What was found

The application treated the address returned by the provider as proof of ownership and used it to attach the identity to an existing account. It did not require the user to already be authenticated in that account, and it did not check whether the provider had verified the address. An attacker able to present a chosen address through the flow could reach an account that was never theirs.

Why it mattered

Full access to another user's account and everything inside it, without needing that user's password and without triggering a password reset email that might have warned them. Multi-factor authentication on the password path did not help, because the attack does not use the password path.

How it was fixed

  • Require an authenticated session before an external identity can be attached to an existing account, and re-authenticate at the point of linking.
  • Treat the provider's address as unverified unless the provider explicitly asserts that it verified it, and never as proof of account ownership on its own.
  • Bind the state parameter to the session that initiated the flow and reject any response that does not match it.
  • Constrain redirect targets to an exact allow list rather than a prefix or a domain suffix match.
  • Notify the account owner out of band whenever a new sign-in method is added.
Check this on your own system

Three things worth doing this week

None of these needs a purchase order. They are the checks that most often turn up something on a system nobody has looked at from the outside.

Check the join, not the parts

Social login is usually fine on its own and the password system is usually fine on its own. The bug lives where they meet. If you have added sign-in methods over time, the linking logic is the first thing to have looked at.

An email address is an identifier, not a credential

Any flow that grants access because an address matches is trusting a value that other systems hand out freely. Ownership has to be proven inside your application, at the moment access is granted.

Second factors only protect the path they sit on

If multi-factor authentication is enforced at password login but not on the single sign-on path or the reset path, then it is optional in practice.

More in this area

Penetration testing

All case studies
Redacted engagement

Password reset and session handling gaps found by testing the whole account lifecycle

Reviewing authentication as a lifecycle rather than a login page surfaced several issues that individually looked minor and together produced a reliable way to hold access to an account after the owner had tried to lock it down. Most of these do not appear in scanner output at all, because every response involved is a legitimate one.

Redacted engagement

SQL injection and stored cross-site scripting behind an authenticated interface

Two classic injection classes, both reachable only after login, which is why neither had ever been reported by an unauthenticated scan. The database defect exposed data across the whole application. The scripting defect ran in the browser of whoever reviewed the affected record, which in this product was always an administrator.

Want to know whether this applies to you?

Tell us what you are running and which of these worries you. We will tell you plainly whether it is worth testing, what it would cost, and when the answer is that you should fix something yourself first.