Listen to this Post

Introduction:
Maester has long been the go‑to PowerShell framework for testing Microsoft Entra ID (formerly Azure AD) and Microsoft 365 security configurations. However, not every admin or security analyst loves PowerShell, and cross‑platform or browser‑only environments often hinder rapid security assessments. Jos Lieben’s new web‑port of Maester solves this by running 175 out of 225 Maester tests directly in your browser using delegated OAuth logins – no PowerShell, no local install, and multi‑tenant capable with progress stored in browser cache. This article dissects how it works, its CORS limitations, and provides step‑by‑step technical guidance to leverage (and extend) browser‑based tenant security testing.
Learning Objectives:
- Understand how delegated login and browser‑based scanning enable PowerShell‑free Entra ID security assessments.
- Identify CORS constraints that block certain API calls and learn practical workarounds (proxies, browser extensions).
- Build and customize your own browser‑based Maester‑style tests using JavaScript, local storage, and proxy bypasses.
You Should Know:
- Delegated Login & Browser‑Based Scanning: How It Works
The web‑port uses OAuth 2.0 implicit or authorization code flow with PKCE to obtain a delegated access token for the logged‑in user. Unlike traditional PowerShell (which often uses app‑only authentication), this method runs entirely in your browser – the token never touches a backend server. The scanner makes fetch() calls to Microsoft Graph and other Entra ID endpoints, mimicking what an authenticated user can see.
Step‑by‑step usage:
- Navigate to the Maester web‑port (shortened link: https://lnkd.in/eurmEACv – expand to actual URL via a service like https://unshorten.me if needed).
- Click “Login with Microsoft” and consent to delegated permissions (e.g.,
User.Read,Policy.Read.All,Directory.Read.All). - After redirect, the scanner automatically runs 175 tests against your tenant. Progress saves in browser
localStorage.
Technical insight – inspect the token:
Open browser DevTools (F12) → Console → type:
// For Chromium or Firefox
console.log(localStorage.getItem('msal.token.keys'));
// Or capture network requests: look for "access_token" in response bodies
On Linux/Windows using `curl` to mimic delegated flow (advanced):
This requires manual token extraction from browser; for automation, use MSAL.js curl -X GET "https://graph.microsoft.com/v1.0/organization" -H "Authorization: Bearer YOUR_DELEGATED_TOKEN"
- Navigating CORS Constraints: Why 50 Tests Are Missing
Cross‑Origin Resource Sharing (CORS) blocks the browser from calling certain Microsoft APIs because they either don’t return the required `Access-Control-Allow-Origin` header or expect a different origin. The web‑port cannot bypass this – hence 175/225 tests run.
Step‑by‑step to identify blocked APIs:
- Open DevTools → Network tab → Reload the scanner page.
- Look for failed (red) requests with CORS errors.
- Note which endpoints are blocked (e.g., some
https://main.iam.ad.ext.azure.com` endpoints).cors-proxy.js
<h2 style="color: yellow;">Workaround – local CORS proxy (Node.js):</h2>
<h2 style="color: yellow;">Create:</h2>.const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express(); app.use('/', createProxyMiddleware({ target: 'https://graph.microsoft.com', changeOrigin: true, onProxyReq: (proxyReq, req, res) => { proxyReq.setHeader('Origin', 'https://your-maester-webapp.com'); } })); app.listen(8080);Run `node cors-proxy.js` and configure the web‑port to use `http://localhost:8080` (requires modifying the web app’s API endpoint variable). On Windows, install Node.js first; on Linux: `sudo apt install nodejs npm && npm install express http-proxy-middleware
-
Multi‑Tenant Progress & Persistent State with Browser Cache
The scanner stores per‑tenant results in `localStorage` using a key derived from the tenant ID. This allows you to scan multiple tenants (e.g., partner environments) without losing previous reports, as long as you don’t clear your cache.
How to manipulate or export progress:
In DevTools Console:
// View all stored results
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key.includes('maester')) console.log(key, localStorage.getItem(key));
}
// Export as JSON
copy(JSON.stringify(localStorage));
// Clear progress for a specific tenant
localStorage.removeItem('maester_tenant_123456');
On Linux/Windows (no direct browser cache access, but you can automate with Puppeteer):
Install Puppeteer npm install puppeteer Script to extract localStorage: see Puppeteer docs
To use this feature effectively: Before scanning a new tenant, either create a separate browser profile or backup your existing `localStorage` using the export snippet above.
- Rebuilding Maester Tests: From PowerShell to TypeScript/JavaScript
The original Maester tests are written in PowerShell (Pester framework). The web‑port rewrites them in JavaScript, checking API responses against security best practices.
Example – test for MFA registration status (PowerShell vs JavaScript):
PowerShell (original):
Describe "MFA Registration" {
It "At least 50% of users should have MFA methods registered" {
$users = Get-MgUser -All | Where-Object {$<em>.UserType -eq 'Member'}
$registered = $users | Where-Object { (Get-MgUserAuthenticationMethod -UserId $</em>.Id).Count -gt 0 }
($registered.Count / $users.Count) -ge 0.5 | Should -Be $true
}
}
JavaScript (web‑port equivalent using Graph API):
async function testMfaRegistration(accessToken) {
const response = await fetch('https://graph.microsoft.com/v1.0/users?$filter=userType eq \'Member\'', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const users = (await response.json()).value;
let registered = 0;
for (const user of users) {
const methodsRes = await fetch(`https://graph.microsoft.com/v1.0/users/${user.id}/authentication/methods`, {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const methods = await methodsRes.json();
if (methods.value.length > 0) registered++;
}
return (registered / users.length) >= 0.5;
}
Step‑by‑step to write your own browser test:
- Obtain delegated token (use MSAL.js or copy from browser).
2. Use `fetch` to call Graph endpoint.
- Assert condition and log result to console or a custom UI.
- Security Risks of Browser‑Based Tenant Scanners & Mitigations
Running third‑party JavaScript in your browser with a delegated Microsoft token introduces risks: token exfiltration via malicious scripts, XSS if the web app is compromised, or phishing lookalike domains.
- Security Risks of Browser‑Based Tenant Scanners & Mitigations
Mitigation steps for end‑users:
- Use a dedicated, clean browser profile or incognito mode.
- After scanning, revoke the OAuth consent from Azure AD:
- Portal → Microsoft Entra ID → Enterprise applications → “Maester Web Port” → Remove permissions.
- Or use PowerShell to revoke:
Revoke-AzureADUserAllRefreshToken -ObjectId <user-object-id>
(AzureAD module) or via Microsoft Graph PowerShell:
Revoke-MgUserSignInSession -UserId <user-id>
On Linux/Windows with `jwt-cli`: Inspect token expiry:
Install jwt-cli (npm install -g jwt-cli) jwt decode YOUR_TOKEN Look for "exp" (expiration timestamp)
Hardening recommendation: Run the web‑port inside a sandboxed container (Firefox Multi‑Account Containers, Chrome with `–no-sandbox` or Windows Sandbox) to isolate tenant tokens from your primary environment.
- Extending the Web‑Port: Adding Custom Tenant Tests
You can build your own browser‑based security test suite for Entra ID by forking the concept.
Step‑by‑step to create a custom test for “Service Principal with high privileges”:- Set up a simple HTML page with MSAL.js for login.
2. After login, call Graph API:
const response = await fetch('https://graph.microsoft.com/v1.0/servicePrincipals?$filter=appOwnerOrganizationId eq null', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const sps = await response.json();
let risky = 0;
for (const sp of sps) {
// Check if SP has Directory.Read.All or Application.ReadWrite.All
const roleRes = await fetch(<code>https://graph.microsoft.com/v1.0/servicePrincipals/${sp.id}/appRoleAssignments`, {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const roles = await roleRes.json();
if (roles.value.some(r => r.appRoleId === 'some-high-privilege-id')) risky++;
}
console.log(</code>Found ${risky} high‑risk service principals<code>);
3. Display results in a
<
div>`. To bypass CORS for any unsupported endpoints, deploy a simple proxy on a cloud function (Azure Function, AWS Lambda) that forwards requests with the original token.
- Hardening Your Entra ID Tenant Against Automated Browser Scanners
Attackers can build similar browser‑based tools to silently assess your tenant from a logged‑in user’s session. Defend using Conditional Access and anomaly detection.
Step‑by‑step hardening commands (Azure CLI & PowerShell):
- Restrict OAuth app registrations:
PowerShell Graph Update-MgPolicyAuthorizationPolicy -AllowedToUseSSPR $false -DefaultUserRolePermissions @{ "AllowedToCreateApps" = $false } - Detect unusual consent activity via Azure Monitor:
Azure CLI az monitor activity-log list --category "Security" --query "[?contains(operationName.value, 'Consent')]"
- Enable Identity Protection user risk policy (Entra ID Portal → Protection → Identity Protection → User risk policy) to block high‑risk sign‑ins.
- Collect audit logs for browser‑based scanners: Look for `UserAgent` strings containing custom JavaScript fetch calls (often missing the `MSAL.js` signature).
Search audit logs via PowerShell Graph Get-MgAuditLogDirectoryAudit -Filter "activityDateTime ge 2025-01-01" | Where-Object {$_.AdditionalDetails -match "Maester|CORS"}Mitigation summary: Regularly review OAuth app permissions (Enterprise applications > “All applications”) and revoke any unrecognized apps that request broad read scopes.
What Undercode Say:
- Key Takeaway 1: The Maester web‑port effectively democratizes Entra ID security testing by eliminating PowerShell dependencies – any auditor with a browser can now run 78% of the original test suite.
- Key Takeaway 2: CORS remains the biggest barrier to full browser‑based API security testing, but local proxies and lightweight backend forwarders can restore missing tests without sacrificing the “no‑install” advantage.
Analysis: This shift from PowerShell to TypeScript reflects a broader trend in security tooling – moving toward lighter, cross‑platform, GUI‑first interfaces that leverage modern browser capabilities. However, OAuth delegated tokens in a JavaScript context introduce subtle risk: malicious extensions or compromised CDNs could exfiltrate tokens undetected. Organizations should treat browser‑based scanners as “semi‑trusted” and enforce just‑in‑time consent expiration. The 50 missing tests (due to CORS) mostly involve legacy endpoints like `main.iam.ad.ext.azure.com` – Microsoft’s ongoing migration to Graph v1.0 will eventually eliminate these gaps. For security professionals, this tool is a perfect example of “defensive innovation” – making security testing accessible while simultaneously highlighting new attack surfaces (phishing via fake scanner portals). Always verify the web‑port’s origin and review requested permissions before consenting.
Prediction:
Within two years, most Microsoft 365 security assessment frameworks will offer a browser‑based, PowerShell‑free tier, powered by WebAssembly and progressive web app (PWA) capabilities. This will accelerate “red teaming for everyone” but also trigger a new class of browser‑based reconnaissance attacks – where malicious OAuth apps mimic legitimate scanners to harvest tenant configurations. Microsoft will likely respond by introducing “scanner‑specific” consent categories (e.g., SecurityAssessment.Read.All) with strict origin binding and automatic revocation after 24 hours. Eventually, browser‑based security testing will merge with serverless cloud scanners (like Azure Automation accounts), offering hybrid execution – JavaScript for quick checks, backend proxies for CORS‑blocked APIs – all managed through a single dashboard. Organizations must adapt by moving from “blocking PowerShell” to “monitoring browser automation and OAuth consent anomalies” as their primary detection strategy.
▶️ Related Video (82% Match):
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Joslieben Maester – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


