# Breach-Check Rubric

How to interpret the outputs from `user-breach-check.sh` and `tenant-sweep.sh`.

## Single-user check — the 10 points

| # | Check | What "clean" looks like | Red flags |
|---|---|---|---|
| 1 | Inbox rules (Graph) | Empty, or only benign filters | ForwardTo / RedirectTo / ForwardAsAttachmentTo set; DeleteMessage+MarkAsRead combos; rules filtered on "password", "bank", "invoice", "CEO name", "security"; rules with name like "." or " " (attacker hiding) |
| 2 | Mailbox settings / auto-reply | Auto-reply disabled or legitimate | Auto-reply active with external audience + unfamiliar message body |
| 3 | Exchange REST (hidden rules, delegates, SendAs, Get-Mailbox forwarding fields) | Only SELF in permissions; no forwarding | **Hidden** inbox rule moving to RSS/Notes/Conversation History; non-SELF FullAccess/SendAs; ForwardingAddress or ForwardingSmtpAddress set to external |
| 4 | OAuth consents + app role assignments | Legitimate apps only (Teams, Outlook mobile, BlueMail, etc.); dates match user history | New consent in attack window; unknown app with `Mail.ReadWrite`, `Files.ReadWrite`, `offline_access`; publisher not verified |
| 5 | Auth methods | All methods predate the attack window | New phone/Authenticator registered within hours of first suspicious sign-in; duplicate entries with the same device name but different createdDateTime |
| 6 | Sign-ins 30d | Consistent US IPs, user's known geography | Any successful sign-in from a country the user never visits; IMAP/POP/Authenticated SMTP client apps (legacy auth); sign-ins from TOR exit nodes or known residential-proxy ranges |
| 7 | Directory audits | Only legit admin/system actions | `Update user` by non-admin principal; password reset the user didn't initiate; auth method change from `Microsoft Substrate Management` is normal but repeated changes are not |
| 8 | Risky users / risk detections | `riskLevel: none` | Any `medium` or `high`; `riskDetail: userPerformedSecuredPasswordChange` just means resolved — check the original detection |
| 9 | Sent items (recent 25) | Normal business correspondence | Blast emails to random external recipients; forwards of internal financial/HR info externally; anything after-hours from an unusual client app |
| 10 | Deleted items (recent 25) | Marketing/spam, routine notifications | Deleted security alerts, password-reset emails, MFA notifications, bounce notices the user wouldn't delete — all signs of attacker cleanup |

### Cross-check rule

If inbox rules and forwarding are clean **but** sign-ins show successful foreign access — attacker may have used OAuth-based access (check OAuth grants) or already extracted data and cleaned up. Pull sent items + deleted items aggressively and check `/auditLogs/signIns/beta` for non-interactive sign-ins.

## Tenant-wide sweep — priorities

| Priority | Signal | Action |
|---|---|---|
| P1 | User with ≥20 failed sign-ins from ≥2 foreign countries | Likely active credential-stuffing target. Reset password, disable SMTP AUTH, monitor. |
| P1 | Successful sign-in from non-US | Verify with user immediately. If not them: force password reset + revoke sessions + full breach check. |
| P2 | New OAuth consent to unfamiliar app in attack window | Review app publisher, scopes, and requesting user. Revoke if unknown. |
| P2 | B2B guest invite to personal email domain (gmail.com, outlook.com, yahoo.com) | Confirm with inviter it's intentional. Guest invites are a known persistence mechanism. |
| P3 | Transport rule created/modified by a non-admin | Transport rules can redirect mail tenant-wide. Review body/actions carefully. |
| P3 | Service principal added by non-admin or by "PowerApps Service" unexpectedly | Usually benign, but worth noting. |
| P4 | Isolated wrong-password attempt from foreign IP | Record and move on. Single attempts are noise unless repeated. |

## False positives to filter out

- `sysadmin@<tenant>` failures during onboarding (error 65001 against any **ComputerGuru** app — Security Investigator, Exchange Operator, User Manager, Tenant Admin, or Defender Add-on).
- `Microsoft Substrate Management` and `Azure MFA StrongAuthenticationService` routinely update user records — those are not attacker activity.
- Our own consent attempts show up as `Consent to application` in directory audits. Filter `sysadmin` + target matching any "ComputerGuru" app display name during the onboarding window.
- `error 50140` "Keep me signed in interrupt" is a browser prompt, not a failed auth.

## When to escalate beyond this tool

- Data exfiltration suspected -> pull Unified Audit Log via Purview (this tool does not access UAL).
- Tenant-wide phishing campaign -> enable Purview Content Search, quarantine messages.
- Domain-joined workstation compromise -> GuruRMM + Bitdefender workflow (see `clients/ace-portables/reports/` for past example).
- Attacker still active and exfiltrating -> consider disabling the user via the `remediate` subcommand and rotating the mailbox password at the same time.
