๐ Recipe ยท SharePoint & OneDrive
Audit SharePoint Sites for Security Issues and Oversharing
Inventory every SharePoint site, flag 'Everyone' and anonymous sharing, and produce a prioritized remediation report
Complexity
Intermediate
Impact
security + compliance + access-review + data-governance + sharepoint
Context
Why This Matters
SharePoint Online is one of the most common sources of data oversharing in Microsoft 365 tenants. Over time, sites accumulate permissions that nobody remembers granting โ 'Everyone except external users' groups, stale guest accounts, anonymous sharing links that never expire, and site owners who left the company years ago.
This recipe walks through a tenant-wide audit of every SharePoint site, focusing on the highest-risk misconfigurations: wide-reaching internal access (Everyone groups), external/anonymous sharing, and missing or orphaned owners. Run it quarterly as part of your access review program, before a compliance audit (SOC 2, ISO 27001, HIPAA), or any time you onboard a new CISO or data protection lead.
When to run this recipe
- Quarterly access reviews
- Pre-audit preparation (SOC 2, ISO 27001, HIPAA)
- After a security incident involving data exposure
- When migrating from a file server to SharePoint
- After enabling or disabling tenant-wide external sharing
Expected Outcomes
After completing this recipe you will have:
- A complete inventory of all SharePoint sites in the tenant (excluding OneDrive personal sites)
- A CSV report listing each site's URL, owners, sharing capability, and flagged findings
- A prioritized list of sites sharing with 'Everyone' or 'Everyone except external users'
- A list of sites with anonymous ('Anyone') sharing enabled
- Identification of orphaned sites (no active owner) and sites with excessive external guests
- Concrete remediation actions for each high-risk site
Risks & Considerations
Before you start
- Permissions matter: To enumerate site-level permissions via Graph, the calling app needs
Sites.FullControl.All. Lower scopes likeSites.Read.Allwill return 403 on/sites/{id}/permissions. Plan the consent step with your security lead. - Do not remediate blindly: 'Everyone except external users' is sometimes intentional (company-wide intranet, all-hands announcements). Review each finding with the site owner before removing access.
- Throttling: Large tenants (1000+ sites) will hit Graph throttling. Use
$select, paginate, and add backoff retries. - Audit log the audit: Anything touching permissions is logged. Coordinate with your SOC so your review activity is not flagged as an attack.
- OneDrive is out of scope here: This recipe intentionally skips personal sites (
/personal/). Audit those separately โ the permission model and remediation flow differ. - Do not change sharing settings during the audit. Collect findings first, then remediate in a controlled change window.
Required Permissions
| Permission | Why It's Needed |
|---|---|
| Sites.FullControl.All | Required to read site-level permissions and sharing capability for every SharePoint site. Lower scopes return 403 on the permissions endpoint. |
| Sites.Read.All | Minimum scope to enumerate sites and read site metadata. Sufficient for the inventory step but not for permission drill-down. |
| Directory.Read.All | Resolve group and user identities referenced in site permissions (e.g., to identify 'Everyone except external users'). |
| SharePoint Administrator role | Required in the SharePoint admin center to view and modify tenant-wide external sharing settings and per-site sharing capability. |
The fastest way to get this done: just ask Dex. Copy the prompt below and paste it into your Dex conversation.
For IT Admins
Paste into Dex Pro
Audit SharePoint security using the admin centers
Step 1 โ Open the SharePoint admin center
Navigate to:
Microsoft 365 Admin Center โ Admin centers โ SharePoint
Or go directly to https://{tenant}-admin.sharepoint.com.
Step 2 โ Review tenant-wide sharing settings
SharePoint Admin Center โ Policies โ Sharing
- Confirm the external sharing slider is set to the most restrictive level your business allows. Anyone (anonymous links) should be disabled unless there is a specific business case.
- Review default link type โ prefer Specific people over Anyone or People in your organization.
- Set link expiration (e.g., 30 days) for Anyone links if they are enabled.
Step 3 โ Inventory all active sites
SharePoint Admin Center โ Sites โ Active sites
- Add the columns Sharing, Primary admin, Sensitivity, and Last activity (days) via the column picker.
- Export the site list: Export โ CSV. This is your starting inventory.
Step 4 โ Identify oversharing
- Sort the exported CSV by Sharing and flag any site set to Anyone or New and existing guests that should not be.
- Filter sites with no Primary admin โ these are orphaned and need a new owner assigned.
Step 5 โ Drill into high-risk sites
For each flagged site, click into the site in the admin center and review:
- Membership tab โ Site owners, members, visitors. Remove Everyone except external users from Owners/Members groups unless intentional.
- Policies tab โ Per-site external sharing. Set to Only people in your organization for sensitive sites (Finance, HR, Legal, Security).
- Sensitivity label โ Apply a label (e.g., Confidential) to enforce inherited protections.
Step 6 โ Check active sharing links
Within the site (not admin center):
Site โ Settings (gear) โ Site permissions โ Advanced permissions settings โ Access requests and invitations
Review and revoke stale guest invitations and anonymous links.
Step 7 โ Document and track remediation
For every finding, record: site URL, finding, owner contacted, remediation action, target date. Revisit in 14 days to confirm closure.
Audit SharePoint using Microsoft Graph
All calls assume base URL https://graph.microsoft.com/v1.0 and a bearer token with Sites.FullControl.All.
1. Enumerate all sites
GET /sites?search=*&$select=id,displayName,webUrl,createdDateTimeUse the search=* wildcard to return every site the app can see. Page through @odata.nextLink until exhausted. Skip any webUrl containing /personal/ to exclude OneDrive.
2. Read site-level permissions
GET /sites/{site-id}/permissionsReturns the permissions granted on the site (typically app-only grants and sharing links). Example response fragment:
{
"value": [
{
"id": "aTowIy5mfG1lbWJlcnNoaXB8...",
"roles": ["read"],
"grantedToIdentitiesV2": [
{ "user": { "displayName": "Everyone except external users" } }
]
}
]
}3. Check sharing capability per site
Graph does not expose per-site sharing capability directly; use the SharePoint REST API:
GET https://{tenant}.sharepoint.com/sites/{site}/_api/site/SharingCapabilityValues: 0 = Disabled, 1 = ExternalUserSharingOnly, 2 = ExternalUserAndGuestSharing (Anyone links), 3 = ExistingExternalUserSharingOnly.
4. List site owners (from the backing group)
GET /groups/{group-id}/ownersFor group-connected sites (most modern sites), owners live on the Microsoft 365 group. Empty owner list = orphaned site.
5. Enumerate guest users with access
GET /sites/{site-id}/drive/root/permissionsOr walk items recursively for item-level sharing links. For tenant-wide guest inventory, combine with /users?$filter=userType eq 'Guest'.
Handling 403s
If you receive 403 accessDenied on /sites/{id}/permissions, the app is missing Sites.FullControl.All. Grant admin consent in Entra โ App registrations โ your app โ API permissions.
Audit SharePoint using PowerShell
The cleanest path is a combination of Microsoft.Graph (for the inventory and cross-tenant data) and PnP.PowerShell (for rich per-site permission drill-down).
Prerequisites
Install-Module Microsoft.Graph -Scope CurrentUser
Install-Module PnP.PowerShell -Scope CurrentUserConnect
Connect-MgGraph -Scopes "Sites.FullControl.All","Directory.Read.All"
Connect-PnPOnline -Url "https://{tenant}-admin.sharepoint.com" -InteractiveStep-by-step
- Enumerate sites โ
Get-PnPTenantSitereturns every site with sharing capability, owner, and storage usage in one call. - Loop each site โ for each, record: URL, owner, sharing capability, template, last modified, storage used.
- Flag oversharing โ sites where
SharingCapabilityis ExternalUserAndGuestSharing (Anyone links) or where the Members group containsc:0(.s|true(Everyone except external users). - Check owners โ sites with empty
Ownerare orphaned. - Export CSV โ one row per site, one column per finding.
The downloadable script below performs all of this end to end and writes a timestamped CSV to the current directory. Run it as a SharePoint Administrator.
Next steps