14.6 Token-Specific Containment
Token-Specific Containment
Token containment is more complex than standard password-reset containment. You must address: refresh tokens, access tokens (the revocation gap), OAuth application tokens, and device-bound tokens. Missing any one leaves the attacker with access.
Required role: User Administrator, Authentication Administrator, Application Administrator.
The containment sequence for token-based attacks
Step 1: Revoke all user refresh tokens.
| |
Blast radius: All sessions terminated. User must re-authenticate everywhere. Per-user.
Verify: SigninLogs | where TimeGenerated > ago(30m) | where UserPrincipalName == "r.williams@northgateeng.com" | where IPAddress == "203.0.113.91" — zero rows.
Step 2: Reset the password. Prevents re-authentication with the old password.
Step 3: Revoke OAuth application consents. This is the step most containment procedures miss.
| |
Blast radius: Removing the application affects all users who consented. Removing only the user’s consent affects only that user. Per-application or per-user.
Step 4: Address the revocation gap. After refresh token revocation, active access tokens remain valid for up to 90 minutes. Options:
Option A (if CAE is enabled): CAE-aware applications evaluate the revocation event and terminate the session within minutes. No manual action needed.
Option B (if CAE is not enabled): The 90-minute gap exists. To close it immediately: disable the user account (Set-AzureADUser -ObjectId "r.williams" -AccountEnabled $false). This forces all resource servers to reject the access token on next evaluation — typically within 5-15 minutes for Graph API and Exchange Online. Re-enable the account after the access token’s natural expiry.
Blast radius of account disable: Total access loss for the user. All sessions terminated. Per-user — severe but temporary.
Rollback: Re-enable the account. Set-AzureADUser -ObjectId "r.williams" -AccountEnabled $true. User re-authenticates with the new password.
Step 5: Check for device registrations.
| |
Remove any devices registered from non-corporate IPs during the compromise window.
Token containment verification
After all steps, verify:
| |
Expected: Zero rows from non-corporate IPs. If results appear: a persistence mechanism was missed. Investigate OAuth apps and device registrations again.
Subsection artifact: The 5-step token containment sequence with verification. This is the containment section of your token investigation playbook — more comprehensive than the M11 containment because it explicitly addresses OAuth persistence and the revocation gap.
Compliance mapping: NIST CSF RS.MI-1 (Incidents are contained). ISO 27001 A.5.26 (Response to incidents).
Knowledge check
Emergency vs standard token revocation
Standard revocation: Revoke-MgUserSignInSession. Invalidates all refresh tokens. The revocation gap (up to 90 minutes) exists — the current access token remains valid until natural expiry.
Emergency revocation (close the gap immediately):
Step 1: Revoke tokens (same as standard).
Step 2: Disable the account: Set-AzureADUser -ObjectId "[USER-OBJECT-ID]" -AccountEnabled $false.
Step 3: Wait 5-15 minutes. Resource servers evaluate the disabled status and reject the access token.
Step 4: Re-enable the account: Set-AzureADUser -ObjectId "[USER-OBJECT-ID]" -AccountEnabled $true.
Step 5: The user re-authenticates with the new password.
When to use emergency revocation: When the attacker is actively exfiltrating data (visible in the Livestream), when the attacker has admin privileges, or when the compromised account has access to highly sensitive resources where 90 minutes of continued access is unacceptable.
When standard revocation is sufficient: The attacker’s activity is historical (not active right now), the compromised account has normal user privileges, and the data exposure risk during the 90-minute gap is acceptable.
| |
Any sign-in attempt after account disable shows ResultType 50057. This confirms the account is locked — including the attacker’s access token being rejected on its next resource request.
Try it yourself
In your test tenant: sign into Outlook Web Access in a browser tab. In a separate session (PowerShell or Entra portal): revoke the user's tokens AND disable the account. Observe: does the OWA session continue working? How long before it stops? Re-enable the account and re-authenticate. This demonstrates the revocation gap (OWA continues briefly after revocation) and the emergency closure (OWA stops within minutes of account disable).
What you should observe
After token revocation only: OWA continues for several minutes (the access token is still valid). After account disable: OWA stops within 5-15 minutes (the resource server evaluates the disabled status). This is the practical difference between standard and emergency revocation.
Check your understanding
1. You revoke tokens and reset the password. Non-interactive sign-ins from the attacker IP continue for 45 minutes, then stop. What happened?