Conditional Access Policy Investigation - Instructions
Purpose
This skill investigates Conditional Access (CA) policy changes in correlation with sign-in failures to detect:
- Legitimate troubleshooting (authorized policy changes to resolve access issues)
- Security control bypass (unauthorized policy modifications to circumvent blocks)
- Privilege abuse (users with admin rights weakening security controls)
The key distinction is whether policy changes were authorized and necessary vs self-service bypass of security controls.
📑 TABLE OF CONTENTS
- [Critical Investigation Rules](#critical-investigation-rules) - Mandatory workflow steps
- [Common Error Codes](#common-error-codes) - Sign-in failure reference
- [CA Policy States](#ca-policy-state-meanings) - Understanding policy modes
- [5-Step Investigation Workflow](#investigation-workflow-pattern) - KQL queries and analysis
- [Real-World Example](#real-world-example-analysis) - Complete walkthrough
- [Critical Mistakes](#critical-mistakes-to-avoid) - What NOT to do
- [Security Recommendations](#security-recommendations) - Remediation guidance
Critical Investigation Rules
When investigating sign-in failures (error codes 53000, 50074) with CA policy correlation:
⚠️ MANDATORY STEPS - DO NOT SKIP:
- Query ALL CA policy changes in chronological order (±2 days from failure time)
- Parse policy state transitions from the JSON (enabled → disabled → report-only)
- Compare failure timeline with policy change timeline
- Verify logical consistency: Ask "does this make sense?"
Key Questions to Answer:
- Was the user blocked BEFORE the policy change?
- Did the policy change resolve the block?
- Who initiated the policy change? (same user = suspicious)
- What was the business justification?
Common Error Codes
| Error Code |
Description |
Typical Cause |
| 53000 |
Device not compliant |
Device not enrolled in Intune or failing compliance checks |
| 50074 |
Strong authentication required |
MFA not satisfied |
| 50074 |
User must enroll in MFA |
MFA not configured for user |
| 530032 |
Blocked by CA policy |
Generic CA policy block |
| 65001 |
User consent required |
Application consent needed |
| 53003 |
Access blocked by CA policy |
Explicit block condition met |
| 70044 |
Session expired |
User needs to re-authenticate |
Error Code Investigation Priority
| Priority |
Error Codes |
Investigation Focus |
| HIGH |
53000, 530032, 53003 |
Device compliance, CA policy blocks - check for policy manipulation |
| MEDIUM |
50074 |
MFA requirements - check if MFA was bypassed |
| LOW |
65001, 70044 |
Consent/session issues - usually not security-related |
CA Policy State Meanings
| State |
What It Means |
Security Impact |
| enabled |
Policy actively enforcing |
Blocks non-compliant access (intended behavior) |
| disabled |
Policy not enforcing |
Security control bypassed - all access allowed |
| enabledForReportingButNotEnforced |
Report-only mode |
Logs violations but doesn't block - defeats purpose |
State Transition Risk Assessment
| Transition |
Risk Level |
Interpretation |
enabled → disabled |
HIGH |
Complete security bypass |
enabled → enabledForReportingButNotEnforced |
MEDIUM-HIGH |
Partial bypass (monitoring only) |
disabled → enabled |
LOW |
Security restored (good) |
enabledForReportingButNotEnforced → enabled |
LOW |
Security strengthened (good) |
Investigation Workflow Pattern
Step 1: Identify Sign-In Failures
Query sign-in failures with CA context:
// Get failures with CA context
union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated between (datetime(<START>) .. datetime(<END>))
| where UserPrincipalName =~ '<UPN>'
| where ResultType != '0'
| where AppDisplayName has '<APPLICATION>' // e.g., "Visual Studio Code"
| project TimeGenerated, IPAddress, Location, ResultType, ResultDescription,
ConditionalAccessStatus, UserAgent
| order by TimeGenerated asc
What to Look For:
ResultType values: 53000, 50074, 530032, 53003
ConditionalAccessStatus: "failure", "notApplied"
- Pattern of repeated failures followed by success
Step 2: Query ALL CA Policy Changes in Timeframe
CRITICAL: Query ±2 days from the first failure time
let failure_time = datetime(<FIRST_FAILURE_TIME>);
let start = failure_time - 2d;
let end = failure_time + 2d;
AuditLogs
| where TimeGenerated between (start .. end)
| where OperationName has_any ("Conditional Access", "policy")
| where Identity =~ '<UPN>' or tostring(InitiatedBy) has '<UPN>'
| extend InitiatorUPN = tostring(parse_json(InitiatedBy).user.userPrincipalName)
| extend InitiatorIPAddress = tostring(parse_json(InitiatedBy).user.ipAddress)
| extend TargetName = tostring(parse_json(TargetResources)[0].displayName)
| project TimeGenerated, OperationName, Result, InitiatorUPN, InitiatorIPAddress,
TargetName, CorrelationId
| order by TimeGenerated asc // CRITICAL: Chronological order
Critical Analysis Points:
- InitiatorUPN: Who made the change? Same user as blocked = suspicious
- TargetName: Which policy was modified?
- TimeGenerated: Did change occur AFTER sign-in failures?
- Order: Always chronological (oldest first) to see cause/effect
Step 3: Parse Policy State Changes
For each CorrelationId from Step 2, get detailed changes:
// Get detailed property changes for a specific policy modification
AuditLogs
| where CorrelationId == "<CORRELATION_ID>"
| extend ModifiedProperties = parse_json(TargetResources)[0].modifiedProperties
| mv-expand ModifiedProperties
| extend PropertyName = tostring(ModifiedProperties.displayName)
| extend OldValue = tostring(ModifiedProperties.oldValue)
| extend NewValue = tostring(ModifiedProperties.newValue)
| project TimeGenerated, PropertyName, OldValue, NewValue
Key Properties to Extract:
- Look for
"state" property in the JSON
- Parse
OldValue and NewValue for state transitions
- Document:
enabled → disabled → enabledForReportingButNotEnforced
Step 4: Extract Policy State from JSON
Manual JSON Parsing:
The OldValue and NewValue fields contain JSON. Look for the "state" field:
{
"state": "enabled",
"conditions": { ... },
"grantControls": { ... }
}
Build the Timeline:
- Extract
"state" from each OldValue and NewValue
- Create chronological list:
enabled → disabled → enabledForReportingButNotEnforced
- Correlate with sign-in failure timeline
Step 5: Security Assessment
Compare timelines and assess intent:
| Pattern |
Interpretation |
Risk Level |
| Failures → Policy Disabled |
User bypassed security control to unblock self |
HIGH - Privilege abuse |
| Failures → Policy Changed to Report-Only |
User weakened security control |
MEDIUM-HIGH - Partial bypass |
| Policy Disabled → Failures Continue |
Cached tokens (5-15 min propagation delay) |
INFO - Expected behavior |
| Policy Changed → No More Failures |
Policy change resolved issue |
Context-dependent - May be legitimate troubleshooting |
| Different user made change |
Admin assisted with access issue |
LOW - Likely legitimate (verify authorization) |
Risk Escalation Criteria:
| Criteria |
Risk Level |
| Same user blocked AND made policy change |
HIGH |
| Policy disabled within 30 minutes of first failure |
HIGH |
| Multiple policies modified |
HIGH |
| Change made outside business hours |
MEDIUM-HIGH |
| No change request ticket/approval |
MEDIUM-HIGH |
| Admin made change for blocked user (with ticket) |
LOW |
Real-World Example Analysis
Scenario: User blocked by device compliance policy, then modifies policy
Timeline
| Time |
Event |
Details |
| 19:05 |
Sign-in failure |
Error 53000: device not compliant |
| 19:06 |
Sign-in failure |
Error 53000: device not compliant |
| 19:07 |
Sign-in failure |
Error 53000: device not compliant |
| 19:09 |
Policy change |
enabled → disabled |
| 19:09 |
Policy change |
disabled → enabledForReportingButNotEnforced |
| 19:12 |
Sign-in failure |
Error 53000 (cached token) |
| 19:14 |
Sign-in success |
Access granted |
Analysis
- ✅ Policy was correctly blocking non-compliant device
- Device compliance policy was enforcing as intended - User's device failed compliance checks (not enrolled or failing policy)
- 🚨 User disabled security control to bypass block
- Same user who was blocked made the policy change - Change occurred within 4 minutes of repeated failures - No approval or change request documented
- ⚠️ User partially reversed by enabling report-only
- Shows some awareness that disabling was too aggressive - But report-only still defeats the purpose (doesn't block)
- ❌ Report-only mode is NOT a valid security posture
- Logs violations but allows non-compliant access - Creates false sense of security (policy "exists" but doesn't protect)
Assessment
| Field |
Value |
| Risk Level |
MEDIUM-HIGH |
| Finding |
Self-service security bypass using privileged role |
| Root Cause |
User's device is non-compliant (not enrolled/failing compliance) |
| Policy Impact |
Device compliance checks now ineffective for all users |
Recommendations
- Immediate Actions:
- Restore policy to enabled state - Verify user's device compliance status - Document incident for security review
- User-Specific:
- Enroll user's device in Intune - Verify device meets compliance requirements - Review if user needs Security Administrator role
- Process Improvements:
- Implement approval workflow for CA policy changes - Create alert for policy state changes (enabled → disabled/report-only) - Review all users with permission to modify CA policies - Consider PIM for Security Administrator role
Critical Mistakes to Avoid
❌ DON'T:
| Mistake |
Why It's Wrong |
| Query only ONE policy change event |
You'll miss the sequence of changes |
| Read policy changes in reverse chronological order |
Confuses cause/effect relationship |
| Assume policy was already disabled |
Must check starting state from OldValue |
| Skip verifying "does this make logical sense?" |
Disabled policies can't block users |
| Ignore the initiator identity |
Same user = suspicious, different admin = verify authorization |
| Focus only on final state |
The transition sequence reveals intent |
✅ DO:
| Best Practice |
Why It Matters |
| Query ALL policy changes in the timeframe |
Complete picture of modifications |
| Order chronologically (oldest first) |
See cause/effect sequence |
| Parse the full JSON for state transitions |
Extract exact policy states |
| Cross-check: blocked user → policy must be enabled |
Logical consistency verification |
| Ask: "Why would user disable this policy?" |
Usually to bypass a legitimate block |
| Check if initiator had authorization |
Ticket, approval, documented reason |
Security Recommendations
When CA Policy Changes Are Detected
1. Determine Legitimacy
- Was the policy change authorized?
- Was there a valid business reason?
- Did the user have approval to make this change?
- Is there a change request ticket?
2. Assess Impact
- How many users affected by policy change?
- What applications/resources are now unprotected?
- How long was the policy disabled/weakened?
- Are there compliance implications (regulatory requirements)?
3. Remediation Actions
| Action |
Priority |
Restore policy to enabled state if unauthorized |
IMMEDIATE |
| Investigate root cause (why was user blocked?) |
HIGH |
| Fix underlying issue (device compliance, MFA enrollment) |
HIGH |
| Review who has permission to modify CA policies |
MEDIUM |
| Implement approval workflows for policy changes |
MEDIUM |
| Create alerts for future CA policy modifications |
MEDIUM |
4. Long-Term Improvements
| Improvement |
Benefit |
| Use PIM for Security Administrator role |
Requires approval for elevated access |
| Implement CA policy change alerts |
Real-time notification of modifications |
| Require multi-admin approval for state changes |
Prevents single-person bypass |
| Document approved procedures |
Clear guidance for legitimate troubleshooting |
| Regular access reviews |
Ensure only necessary users have CA admin rights |
Prerequisites
Required MCP Servers
This skill requires:
- Microsoft Sentinel MCP - For KQL queries against SigninLogs and AuditLogs
- mcpsentinel-dataquerylake: Execute KQL queries - mcpsentinel-datasearchtables: Discover table schemas
Required Data Sources
- SigninLogs - Interactive sign-in events with CA status
- AADNonInteractiveUserSignInLogs - Non-interactive sign-in events
- AuditLogs - CA policy modification events
Required Permissions
To view CA policy changes in AuditLogs, ensure:
- Sentinel workspace has AuditLogs ingestion enabled
- User has appropriate RBAC to query the workspace
Integration with Other Skills
CA Policy Investigation often follows a user-investigation:
- Run user-investigation skill → Identifies sign-in failures
- Notice CA-related error codes → 53000, 50074, 530032
- Run ca-policy-investigation skill → Correlate failures with policy changes
- Document findings → Security assessment with remediation recommendations
Key Integration Points:
- Sign-in failure data comes from user investigation
- CA policy changes are NEW queries specific to this skill
- Assessment combines timeline correlation with policy state analysis