Query Details
// Hunt : M365 - OneDrive Stale Guest Access (90d no activity since invite)
// Purpose : Find guest accounts that were given access to OneDrive/SharePoint
// resources over 90 days ago but show no subsequent access activity.
// Stale guest accounts represent an unrevoked attack surface.
// Tables : OfficeActivity
// Period : P90D
//==========================================================================================
let LookbackDays = 90d;
let StaleDays = 30; // inactive for 30+ days after invite = stale
// All guest invitations in the window
let GuestInvitations = OfficeActivity
| where TimeGenerated > ago(LookbackDays)
| where RecordType in ("SharePoint", "OneDrive", "MicrosoftTeams")
| where Operation in (
"SharingInvitationCreated", "AddedToSecureLink",
"MemberAdded", "InviteAccepted")
| where TargetUserOrGroupName has "#EXT#"
or TargetUserOrGroupName has "guest"
| extend GuestUPN = tostring(TargetUserOrGroupName)
| summarize InviteDate = min(TimeGenerated), InviteCount = count()
by GuestUPN, Site_Url;
// All guest access activity
let GuestActivity = OfficeActivity
| where TimeGenerated > ago(LookbackDays)
| where RecordType in ("SharePoint", "OneDrive", "SharePointFileOperation", "OneDriveFileOperation")
| where UserId has "#EXT#"
| where Operation in (
"FileAccessed", "FileDownloaded", "FileViewed",
"FilePreviewed", "PageViewed")
| summarize LastActivity = max(TimeGenerated) by UserId, Site_Url;
// Stale = invited but last activity was > StaleDays ago OR no activity at all
GuestInvitations
| join kind=leftouter GuestActivity
on $left.GuestUPN == $right.UserId and $left.Site_Url == $right.Site_Url
| extend
DaysSinceActivity = iif(isnotnull(LastActivity),
datetime_diff("day", now(), LastActivity),
datetime_diff("day", now(), InviteDate))
| where isnull(LastActivity) or DaysSinceActivity >= StaleDays
| project
GuestUPN,
Site_Url,
InviteDate,
LastActivity,
DaysSinceActivity,
InviteCount
| sort by DaysSinceActivity desc
This query is designed to identify guest accounts that were invited to access OneDrive or SharePoint resources but have not shown any activity for a significant period, specifically over 90 days since their invitation. Here's a simple breakdown of what the query does:
Lookback Period: The query examines data from the past 90 days.
Stale Guest Definition: A guest account is considered "stale" if it has been inactive for more than 30 days after being invited.
Guest Invitations: The query first gathers all guest invitations within the 90-day window. It looks for operations related to guest invitations, such as "SharingInvitationCreated" or "InviteAccepted," and identifies guests by checking for "#EXT#" or "guest" in their usernames.
Guest Activity: It then collects any activity from these guest accounts within the same period, focusing on actions like "FileAccessed" or "PageViewed."
Identify Stale Accounts: The query identifies guests who either have no recorded activity or whose last activity was more than 30 days ago. It calculates the number of days since the last activity or since the invitation if there's no activity.
Output: The results include details such as the guest's username, the site URL they were invited to, the invitation date, the last activity date, the number of days since the last activity, and the count of invitations. The results are sorted by the number of days since the last activity, in descending order.
In summary, this query helps identify guest accounts that may pose a security risk due to inactivity, allowing administrators to review and potentially revoke unnecessary access.

David Alonso
Released: March 18, 2026
Tables
Keywords
Operators