npx claudepluginhub wyre-technology/msp-claude-plugins --plugin m365This skill uses the workspace's default tool permissions.
Security checks are among the most high-value tasks an MSP can perform in a customer's M365 tenant. Account compromises, inadequate MFA coverage, and misconfigured mail rules are the leading causes of M365 security incidents. This skill covers the key checks and indicators that separate a secure tenant from a vulnerable one.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Designs, implements, and audits WCAG 2.2 AA accessible UIs for Web (ARIA/HTML5), iOS (SwiftUI traits), and Android (Compose semantics). Audits code for compliance gaps.
Security checks are among the most high-value tasks an MSP can perform in a customer's M365 tenant. Account compromises, inadequate MFA coverage, and misconfigured mail rules are the leading causes of M365 security incidents. This skill covers the key checks and indicators that separate a secure tenant from a vulnerable one.
MFA enrollment lives on the authentication/methods endpoint per user. Users with only a passwordAuthenticationMethod entry have no MFA.
GET /v1.0/users/{userId}/authentication/methods
Response — user WITH MFA:
{
"value": [
{
"@odata.type": "#microsoft.graph.microsoftAuthenticatorAuthenticationMethod",
"id": "aad-method-id",
"displayName": "iPhone",
"createdDateTime": "2023-06-01T10:00:00Z"
},
{
"@odata.type": "#microsoft.graph.passwordAuthenticationMethod"
}
]
}
Response — user WITHOUT MFA (vulnerable):
{
"value": [
{
"@odata.type": "#microsoft.graph.passwordAuthenticationMethod"
}
]
}
Use Microsoft Graph Reports for tenant-wide MFA status:
GET /v1.0/reports/authenticationMethods/userRegistrationDetails
Response per user:
{
"id": "user-guid",
"userPrincipalName": "jsmith@contoso.com",
"isMfaRegistered": true,
"isMfaCapable": true,
"isSsprRegistered": false,
"methodsRegistered": ["microsoftAuthenticator", "softwareOath"]
}
This is the fastest path to a full tenant MFA audit.
| Method | Security Level | Notes |
|---|---|---|
| FIDO2 hardware key | Highest | Phishing-resistant |
| Windows Hello for Business | Highest | Device-bound |
| Microsoft Authenticator (passwordless) | High | Number matching recommended |
| OATH hardware token | High | |
| Microsoft Authenticator (OTP) | Medium | Better than SMS |
| Software OATH (other app) | Medium | |
| SMS/Phone | Low | Susceptible to SIM swap |
| Password only | None | Unacceptable for business |
GET /v1.0/identityProtection/riskyUsers?$filter=riskState eq 'atRisk'&$select=id,userPrincipalName,riskLevel,riskState,riskLastUpdatedDateTime
Risk Levels: low, medium, high
GET /v1.0/auditLogs/signIns?$filter=riskLevelDuringSignIn ne 'none'&$select=userPrincipalName,riskLevelDuringSignIn,location,createdDateTime&$top=50
POST /v1.0/identityProtection/riskyUsers/dismiss
Content-Type: application/json
{
"userIds": ["user-guid"]
}
GET /v1.0/auditLogs/signIns?$filter=userPrincipalName eq 'user@contoso.com'&$select=createdDateTime,userPrincipalName,ipAddress,location,status,clientAppUsed,riskLevelDuringSignIn&$top=20&$orderby=createdDateTime desc
Key fields for incident response:
status.errorCode: 0 = success, nonzero = failureipAddress and location for geolocation anomaliesclientAppUsed — legacy auth clients are high riskconditionalAccessStatus: notApplied = CA policy gapAttackers often create hidden inbox rules to forward mail or hide replies. Check for:
GET /v1.0/users/{userId}/mailFolders/inbox/messageRules
Red flags:
{
"displayName": "hidden rule",
"conditions": { "subjectContains": ["invoice"] },
"actions": { "forwardTo": [{ "emailAddress": { "address": "attacker@external.com" } }] },
"isEnabled": true
}
Legacy auth protocols (IMAP, POP3, SMTP AUTH, basic auth) bypass MFA. Identify users still using them:
GET /v1.0/auditLogs/signIns?$filter=clientAppUsed eq 'IMAP' or clientAppUsed eq 'POP3' or clientAppUsed eq 'Exchange ActiveSync'&$select=userPrincipalName,clientAppUsed,createdDateTime&$top=100
Recommended: Block legacy auth via Conditional Access policy.
Check if CA policies are configured:
GET /v1.0/identity/conditionalAccess/policies?$select=id,displayName,state,conditions,grantControls
state values: enabled, disabled, enabledForReportingButNotEnforced (report-only)
MSP baseline CA policies to verify exist:
Get the tenant's Microsoft Secure Score:
GET /v1.0/security/secureScores?$top=1
Response:
{
"value": [{
"currentScore": 52.4,
"maxScore": 120.0,
"averageComparativeScores": [
{ "basis": "AllTenants", "averageScore": 38.2 }
]
}]
}
Score improvement recommendations:
GET /v1.0/security/secureScoreControlProfiles?$select=title,maxScore,implementationStatus,controlCategory
When a user reports suspicious activity, check these in order:
| Check | Command | Red Flag |
|---|---|---|
| Recent sign-ins | GET /auditLogs/signIns | Unfamiliar IP, country, time |
| MFA changes | GET /auditLogs/directoryAudits | MFA method added/removed |
| Inbox rules | GET /mailFolders/inbox/messageRules | External forwarding |
| Sent items | GET /messages from Sent folder | Phishing sent from account |
| OAuth apps | GET /oauth2PermissionGrants | Unknown app granted access |
POST /v1.0/users/{id}/revokeSignInSessions| Task | Microsoft Graph Permission |
|---|---|
| MFA registration report | UserAuthenticationMethod.Read.All |
| Authentication methods | UserAuthenticationMethod.Read.All |
| Sign-in logs | AuditLog.Read.All |
| Risky users | IdentityRiskyUser.Read.All (P2) |
| Conditional access | Policy.Read.All |
| Security score | SecurityEvents.Read.All |
| Revoke sessions | Directory.ReadWrite.All |