prowler-cloud/prowler
View on GitHub[New Check]: At least one Conditional Access policy must explicitly target Azure DevOps
Open
#11067 opened on May 6, 2026
feature-requestgood first issuenew-checkprovider/m365
Description
Existing check search
- I have searched existing issues, Prowler Hub, and the public roadmap, and this check does not already exist.
Provider
Microsoft 365
New provider name
No response
Service or product area
entra
Suggested check name
entra_conditional_access_policy_explicitly_targets_azure_devops
Context and goal
- Security condition to validate: At least one enabled Conditional Access policy explicitly includes the Azure DevOps cloud application (
appId 499b84ac-1321-427f-aa17-267ca6975798) inconditions.applications.includeApplications. The catch-all value"All"does not count as explicit targeting for this check. - Why it matters: Azure DevOps is a high-value sign-in surface (source code, build pipelines, secrets, service connections to production). Operators frequently rely on a single "All cloud apps" Conditional Access policy and assume it covers Azure DevOps; in practice many organisations want a tighter, dedicated policy for Azure DevOps (different MFA prompts, device-compliance requirements, location restrictions, or session controls) because Azure DevOps clients — including the CLI, IDE plug-ins and PAT-based tooling — behave differently from a typical browser sign-in. This check enforces that an explicit Azure DevOps Conditional Access policy exists, so operators surface the decision and don't rely on the "All cloud apps" sweep alone.
- Resource involved: Microsoft Entra Conditional Access policies and their
conditions.applications.includeApplicationscollection.
Expected behavior
- Resource or scope to evaluate: All Conditional Access policies whose
stateisenabled. For each, inspectconditions.applications.includeApplications. - PASS when: at least one enabled policy lists the Azure DevOps
appId 499b84ac-1321-427f-aa17-267ca6975798inincludeApplications. - FAIL when: no enabled policy lists that
appIdexplicitly. A policy whoseincludeApplicationsonly contains"All"does not satisfy this check, by design — the goal is to verify a deliberate, dedicated decision was taken about Azure DevOps. - MANUAL when: not applicable.
- Exclusions / edge cases:
- Report-only policies are out of scope:
state = enabledForReportingButNotEnforcedpolicies do not enforce anything and should not be counted as protection. - The check makes no claim about what the matching policy enforces (block vs require MFA vs require compliant device); it only verifies an explicit-targeting policy exists. Whether the policy is itself secure is the responsibility of other Conditional Access checks already in Prowler.
- Report-only policies are out of scope:
References
- Microsoft Graph v1.0 — Conditional Access policy resource: https://learn.microsoft.com/en-us/graph/api/resources/conditionalaccesspolicy?view=graph-rest-1.0
- Microsoft Graph v1.0 —
conditionalAccessApplications(includeApplications/excludeApplications): https://learn.microsoft.com/en-us/graph/api/resources/conditionalaccessapplications?view=graph-rest-1.0 - Azure DevOps — Manage Conditional Access for Azure DevOps Services: https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/manage-conditional-access
- Verify first-party Microsoft applications and their sign-in events (Azure DevOps
appIdlisted): https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in
Suggested severity
Medium
Additional implementation notes
- Existing patterns to follow: Reuse the Conditional Access iteration pattern from
entra_conditional_access_policy_mfa_enforced_for_guest_usersandentra_conditional_access_policy_directory_sync_account_excluded(prowler/providers/m365/services/entra/). The existingConditionalAccessPolicymodel already exposesstate,conditions.applications.includeApplications, andconditions.applications.excludeApplications— no service change required. - Permissions / scopes: No additional permissions beyond Prowler's M365 baseline (
Policy.Read.Allalready grants reads against Conditional Access policies). - PowerShell is NOT needed; this check uses the Microsoft Graph data already loaded by the entra service.
- App ID constant:
499b84ac-1321-427f-aa17-267ca6975798is Microsoft's stable, tenant-independent service principalappIdfor Azure DevOps Services (documented in the first-party Microsoft applications list referenced above). Hard-code it as a module-level constant in the check. - Metadata: follow the M365 metadata schema used by sibling checks under
entra/.