The v1 CIS auditor, extended from on-prem to the cloud tenant — deterministic, read-first, reproducible. And an honest record of where the platform drew the line.
The v1 CIS auditor covered the on-prem Windows side — 60 controls on a Domain Controller via WinRM and PowerShell. It said nothing about the cloud: Microsoft Entra ID, where identities, MFA, Conditional Access, and privileged-access controls actually live in a hybrid setup.
v2 extends the same JSON-driven, deterministic engine to the tenant. Instead of PowerShell over WinRM, the collector pulls live tenant state from the Microsoft Graph API using a service principal, and the same comparison engine evaluates it against Entra ID / CIS controls — no code changes to the core, and no AI model invoked during the audit. What follows is the real result of that audit on a Microsoft 365 Developer Program tenant: what the platform let us read, what it let us fix, and where it refused the write.
Final state of the remediated Developer Program tenant, re-read from the live API after each write. Green changed as intended; red blocked at the platform tier.
A distinct, reusable finding about how Microsoft 365 Developer Program tenants expose Conditional Access. This is a different kind of ceiling from the P1/P2 feature-level restrictions (PIM, Identity Protection) — and it matters for anyone building or testing automation against Developer tenants.
| API surface | Developer Program tenant | Commercial / paid tenant |
|---|---|---|
| CA policy read GET conditionalAccessPolicies | 200 (empty list) | 200 |
| CA policy write POST conditionalAccessPolicies | 403 "not licensed" | 201 |
| MFA method flags PATCH authenticationMethodsPolicy | 204 | 204 |
| Registration-enforcement PATCH registrationEnforcement | 400 "invalid" | 204 |
| PIM / Identity Protection (P2-gated) | AadPremiumLicenseRequired | licensed |
Two separate ceiling classes:
AadPremiumLicenseRequired and are simply not evaluated; there is no write surface to probe.Three findings, in the order they were discovered. Every number below was verified from the live tenant (re-read after each write), not from intent.
The free-tier MFA method configuration is writable in a Developer tenant, and this fix landed and persisted — PATCH authenticationMethodsPolicy returned HTTP 204, confirmed by a follow-up read.
| Method | Before | After |
|---|---|---|
| enabled | disabled | |
| TemporaryAccessPass | enabled | disabled |
| FIDO2 isAttestationEnforced | false | true |
| MicrosoftAuthenticator | enabled | kept |
| SoftwareOath | enabled | kept |
| SMS / Voice | disabled | already off |
Effect: the two most phishable strong-auth methods (email one-time code, 6-hour TAP) are off the tenant; any completed MFA must be app- or certified-hardware-backed.
An earlier pass of this audit recommended two fixes that assumed a paid/licensed capability was provisionable in a no-license Developer tenant — until challenged to verify the claim against live tenant data:
That was incorrect. This is a Microsoft 365 Developer Program tenant (subscribedSkus = [], assignedLicenses = 0/23) — it cannot provision P1/P2 at all (no trial, no self-serve subscription). The read API for P2-gated features still works; the write / activation path is gated by tenant class — the same split documented in the technical note above.
How it was caught:
subscribedSkus: [], 0/23 user licenses assigned. The "assign P2" fix had nothing to assign.GET → 200 while CA POST → 403 under the same scoped token — proved a tenant-class gate, not a scope / consent problem.Two items could not be remediated in this tenant, with the exact responses:
PATCH authenticationMethodsPolicy → registrationEnforcement…state = active → HTTP 400 "The configured RegistrationEnforcement is invalid." Retried on v1.0 and beta across four payload shapes — consistently rejected.POST conditionalAccessPolicies → HTTP 403 "Your tenant is not licensed for this feature. Please upgrade your subscription." Retried with enabled, disabled, and minimal-body variants — consistently rejected.Root cause: both are licensed capabilities the Developer Program tier does not expose for writes. Not scope (the token carried Policy.ReadWrite.ConditionalAccess / Policy.ReadWrite.AuthenticationMethods), not consent (admin-consented), not payload (multiple shapes). A platform-tier gate.
| Metric | Before | After |
|---|---|---|
| Weak MFA methods (Email + TAP) enabled | 2 | 0 |
| FIDO2 attestation enforced | no | yes |
| Conditional Access policies | 0 | 0 (platform-gated) |
| MFA registration enforcement | inactive | inactive (platform-gated) |
| Users with a registered MFA method | 0 / 23 | 0 / 23 |