The Three Scripts I Found Injecting Themselves Into Our Entra Sign-In Page

When I went looking for scripts that might break when Microsoft hardens Entra's sign-in page, I started in the wrong place. The JavaScript field doesn't exist in company branding—it never has—and that realization reframed…

I went looking for the JavaScript field in Entra’s company branding. It doesn’t exist. It never has. That was the first thing the afternoon taught me, and it reframed the whole exercise.

Here’s what kicked it off. Petri reported that Microsoft is moving to block script injection on Entra ID sign-in pages — the login.microsoftonline.com family of hostnames you hit during authentication. No published rollout date, no Message Center ID I could point at, just the direction of travel: the browser will be told, firmly, to only run the scripts Microsoft itself serves. Everything else gets blocked. Think of it as a Content-Security-Policy clamp on the most security-sensitive page in your tenant.

My job that afternoon was simple on paper. Find out what, if anything, we inject into that page, and decide whether it’s about to stop working. What I didn’t expect was to spend the first twenty minutes looking in entirely the wrong place.

The wrong turn, first

My instinct — and I suspect yours, if you read the same briefs I do — was to open Entra admin center → Company branding and look for the custom JavaScript box. Surely that’s where our “scripts” live. So I clicked into the branding config, found the custom CSS field, the sign-in logos, the background image, the footer hyperlinks, the self-service password reset text…

…and no JavaScript anywhere. Because Entra company branding never let you add arbitrary JavaScript. You get CSS, images, and text. That’s the whole menu. CSS can’t run code; it can only style the page.

Which led to the uncomfortable realization that made the rest of the day make sense: if a script is running on our sign-in page, it is not coming from Microsoft and it is not coming from our branding config. It is coming from somewhere between the user’s browser and Microsoft’s servers. A browser extension. A proxy. A wrapper. Something sitting in the path, slipping code into the envelope while it’s in transit.

That is exactly the position a phishing kit occupies. It’s exactly the position an adversary-in-the-middle toolkit occupies. And it’s why Microsoft is doing this at all — the sign-in page is where credentials and MFA responses get entered, so anything with the power to inject script there has the power to read or rewrite the login. The hardening doesn’t care whether the injected script is your friendly analytics beacon or an overlay harvesting passwords. From the browser’s point of view they’re identical. That’s the point.

What I actually found, roughly in order

Once I was looking in the right place — the browser, not the portal — three things surfaced over the next hour.

One: a session-recording analytics extension. Marketing had, at some point, convinced IT to deploy a web-analytics browser extension to capture “the full user journey.” Turns out the full user journey included the sign-in page. It injected a recorder script into every page, authentication included. This breaks immediately once the clamp lands. It also, quietly, meant a third party was recording keystrokes on our login screen, which is a sentence that should end any debate about whether to keep it.

Two: an accessibility widget delivered by a reverse proxy. An old SSO-branding vendor we’d half-decommissioned was still wrapping some traffic and injecting an accessibility toolbar. Legitimate intent, genuinely useful for some users — and it will break, because it works by inserting script into Microsoft’s page. Of the three, this is the one that’ll generate a help-desk ticket from someone who relies on it, so it needs a real answer, not just removal.

Three: our custom CSS in company branding. This one is fine. It’s native, Microsoft serves it, it isn’t injected from outside, and it’s styling rather than script. Our logo, colours, and footer links survive untouched. Worth stating plainly, because the easy panic reaction is to assume all customization is at risk. It isn’t. Native branding stays.

So: two casualties, one false alarm. For most tenants I’d wager the number is zero casualties, because most tenants never injected anything in the first place. This is a subset problem. But if you’re in the subset, you really want to know before the browser console starts throwing CSP violations on your login screen.

The audit I ran to confirm the branding half

I couldn’t query “what random extension is injecting script on 40,000 managed browsers” from Graph — that’s an endpoint-management question, and I’ll come back to it. But I could confirm the native branding side cleanly, and rule out the false alarm for every locale we’d configured. Read-only, so no guard rails needed beyond behaving yourself:

audit.ps1PowerShell
# Audit Entra company branding across all configured locales.
# Read-only. Confirms what Microsoft natively serves on the sign-in page.
Connect-MgGraph -Scopes "Organization.Read.All" -NoWelcome
​
try {
    $org = Get-MgOrganization -ErrorAction Stop | Select-Object -First 1
    $orgId = $org.Id
​
    # -All handles pagination; a tenant can have many localized brands.
    $locales = Get-MgOrganizationBrandingLocalization -OrganizationId $orgId `
        -All -ErrorAction Stop
​
    if (-not $locales) {
        Write-Host "No branding localizations configured. Nothing custom served." -ForegroundColor Yellow
    }
​
    foreach ($loc in $locales) {
        [pscustomobject]@{
            Locale            = $loc.Id
            HasCustomCss      = [bool]$loc.CustomCssRelativeUrl
            SignInPageText    = $loc.SignInPageText
            UsernameHintText  = $loc.UsernameHintText
            BackgroundImage   = [bool]$loc.BackgroundImageRelativeUrl
        }
    }
}
catch {
    Write-Error "Branding query failed: $($_.Exception.Message)"
}
finally {
    Disconnect-MgGraph | Out-Null
}

What you’re confirming here is reassuring: everything this returns is CSS, text, and images that Microsoft hosts and serves. None of it is executable script. None of it is in the blast radius. If this is the only “customization” you have, you can close the tab and get on with your life.

The injection risk lives outside Graph’s reach, so the second half of the audit was a different toolset entirely. I pulled the list of force-installed browser extensions from Intune / our management policies, and I checked whether any egress proxy or “SSO branding” appliance was still wrapping traffic to the Microsoft login hostnames. That’s where both casualties were hiding. If you run extensions via policy, your extension inventory is the single most useful thing to look at — far more than anything in the Entra portal.

Testing before the clamp arrives

Because there’s no date I’d stake my name on, I didn’t wait for the change to tell me what breaks. I opened a browser profile with our managed extensions loaded, hit the sign-in page, opened the console, and watched. Anything injecting script into Microsoft’s page shows up as a mismatch between the page’s origin and the script’s origin — and once CSP tightens, those same scripts will log as blocked violations instead of running. You can rehearse the failure now by reading the console; you don’t need the feature flag flipped to see who the offenders are.

I’d also strongly suggest doing the real validation in a pilot tenant or a pilot ring of users once Microsoft does publish this in Message Center, rather than discovering it in production. Watch the Message Center. When the notice lands it’ll carry the actual rollout window and the affected surfaces — use that, not my afternoon, as your timeline.

What I’d tell you before you start

Stop looking in the Entra portal for a JavaScript setting. It isn’t there, and the hunt wastes the first twenty minutes. The scripts, if you have any, are injected from the browser or the network path, and that’s a browser-management and proxy question, not a branding one.

Separate the two halves early: native branding (CSS, logos, text) survives and needs no work; injected script (extensions, proxies, wrappers) is the thing that dies. Don’t let the first panic sweep up the former with the latter.

For the genuinely useful casualties — the accessibility widget, the analytics you actually need — move the function to where it belongs. Analytics and monitoring go after authentication, on pages you control, not spliced into Microsoft’s login flow. Accessibility goes to native OS and browser assistive tech, or to post-login app surfaces. If a vendor’s only delivery mechanism is injecting script into someone else’s sign-in page, that was always borrowed time.

And the part that actually made me glad about the change: the exact capability this breaks is the one phishing kits rely on. If your monitoring tool and an adversary-in-the-middle attack both look identical to the browser, the browser is right to distrust both. Losing a session recorder is a cheap price for closing that door.