Skip to content

Lab: Whose email is it? (multi-tenant OAuth)

Difficulty: easy. Time: 10 to 20 minutes. Run it: node tenant-trust.mjs (lab folder), then open http://localhost:4101/.

A small expense app lets people sign in with tokens from a mini identity provider. Anyone can create their own tenant at that provider and add users to it. The app checks that tokens are genuine, then decides who you are. The Contoso tenant has an administrator, [email protected], and you have no Contoso credentials.

Goal: read the flag from GET /admin.

Hint 1

Read / for the endpoint list. Look at what the identity provider lets you control in a tenant you create.

Hint 2

The app verifies the token signature against the provider’s keys. Ask what else it should have verified, and which claim it uses to find your account.

Every tenant admin controls the claims of their own users. In Entra that includes the email claim, which Microsoft describes as controllable by tenant administrators and sometimes users. An app that takes a valid token from any tenant and then looks the user up by email lets an attacker in their own tenant claim to be anyone.

Solution and fix (spoilers)
  1. Create a user in your own tenant with the victim’s email: POST /idp/evil/users {"username":"mallory","email":"[email protected]"}.
  2. Get a token for that user and send it to POST /login. The signature is valid, the audience matches, and the app finds the admin account by email.
  3. Call /admin with the returned session.

The fix is in the --fixed build: only accept tokens from tenants you expect, and key your accounts on the immutable pair tid plus oid, never on email, preferred_username or unique_name.

If your app, or an app you review, logs sign-ins by email, look for the same address arriving from more than one tid. In Entra sign-in logs, a user principal that has always signed in from your tenant suddenly appearing from another home tenant is the shape to hunt. The AADSTS50020 page covers the error you see when such accounts are not allowed in.