Notion Hardening Guide
Collaboration platform hardening for Notion including SAML SSO, workspace security, DLP, AI and MCP connection governance, and audit logging
Overview
Notion is a leading collaboration and productivity platform used by millions of users for documentation, project management, and knowledge sharing. As a repository for organizational knowledge and sensitive business information, Notion security configurations directly impact data protection and information governance.
Intended Audience
- Security engineers managing collaboration platforms
- IT administrators configuring Notion Enterprise
- GRC professionals assessing collaboration security
- Workspace administrators managing access controls
How to Use This Guide
- L1 (Crawl): Essential controls for all organizations
- L2 (Walk): Enhanced controls for security-sensitive environments
- L3 (Run): Strictest controls for regulated industries
Scope
This guide covers Notion workspace and organization security including SAML SSO, SCIM provisioning, data protection, and workspace permissions.
Table of Contents
- Authentication & SSO
- Organization Security
- Data Protection
- Monitoring & Compliance
- Compliance Quick Reference
1. Authentication & SSO
1.1 Configure SAML Single Sign-On
Profile Level: L1 (Crawl)
| Framework | Control |
|---|---|
| CIS Controls | 6.3, 12.5 |
| NIST 800-53 | IA-2, IA-8 |
Description
Configure SAML SSO to centralize authentication for Notion users.
Rationale
Why This Matters:
- Centralizing Notion logins in your corporate IdP applies MFA, conditional access, and session policy to every workspace member from a single control point
- Without SSO, each user keeps a separate Notion password that lives outside IdP oversight and can be phished or reused from a breached service
- Domain-verified SAML ties Notion identities to your authoritative directory so access decisions follow the same governance as the rest of your stack
- Workspaces hold product specs, roadmaps, contracts, and internal knowledge — a single account takeover can expose all of it
Attack Prevented: Credential stuffing, phishing, password reuse, MFA bypass
Prerequisites
- Notion Business or Enterprise plan
- At least one verified domain
- SAML 2.0 compatible IdP
ClickOps Implementation
Step 1: Verify Domain
- Business: first go to Settings → General and remove every entry under Allowed email domains — Notion requires this before SAML SSO can be set up on a Business workspace
- Navigate to: Settings → Identity → Domain management → Verified domains → Add domain, then verify your organization’s domain
- Domain verification is required before SSO setup — Enable SAML SSO stays disabled until a domain is verified
Step 2: Access SSO Configuration
- For Business: Navigate to Settings → Identity → SAML single sign-on (SSO) and use Enable SAML SSO / Edit SAML SSO configuration
- For Enterprise: Open the workspace switcher → Manage organization → General tab → SAML configurations
Step 3: Configure SAML Settings
- Copy the Assertion Consumer Service (ACS) URL
- Enter in your IdP portal
- Configure IdP with:
- ACS URL from Notion
- Entity ID
- Any SAML 2.0 IdP works; Notion’s Set up Identity Provider (IdP) for SAML SSO article, linked from SAML SSO configuration, covers provider-specific setup
Step 4: Enter IdP Details
- Provide either IdP URL or IdP metadata XML
- Complete configuration
- Test SSO authentication
Time to Complete: ~1 hour
Automation: ClickOps only — Notion exposes no write interface for this setting: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
1.2 Enforce SAML SSO
Profile Level: L2 (Walk)
| Framework | Control |
|---|---|
| CIS Controls | 6.3 |
| NIST 800-53 | IA-2 |
Description
Require SAML authentication for all workspace members.
Rationale
Why This Matters:
- Configuring SSO without enforcing it leaves email/password and social logins active as parallel paths that skip IdP controls
- Requiring “Only SAML SSO” closes those bypass routes so every member authenticates through your IdP’s MFA and conditional access
- Attackers target the weakest enabled login method; removing alternatives shrinks the authentication attack surface to one governed path
- The deliberate owner email-login exception preserves break-glass recovery without re-opening daily logins to weaker methods
Attack Prevented: SSO bypass, credential stuffing, phishing, account takeover via fallback login
ClickOps Implementation
Step 1: Configure Login Method
- Navigate to: Settings → Identity → SAML single sign-on (SSO) → Login method
- Default login method is Any method
- Change to Only SAML SSO
Step 2: Require SAML Authorization for Workspace Access (Enterprise)
- Enable Require SAML SSO authorization for workspace access
- This mandates SAML authentication for workspace access regardless of a user’s email domain, so it does not depend on domain verification and — in Notion’s words — “enables safer external collaboration in your workspace”
- Before enabling, confirm every member exists in your IdP; Notion warns explicitly that missing members are locked out of the workspace
Step 3: Understand Exceptions
- Workspace owners can always log in with a password or passkey (the console states: “Workspace owners can always log in with a password or passkey”), so they can modify or disable the SAML configuration during an IdP outage
- Protect those owner accounts accordingly — they are the standing bypass (see 2.3)
- The configuration can be changed to re-enable other methods, so treat changes to it as an audited event (see 4.1)
Validation & Testing
Attempt a login with email/password as a non-owner member and confirm it is refused. Then test with an external collaborator on a non-verified domain and confirm they are routed through SAML — this is the behavior that supersedes the older guidance that external collaborators could not authenticate via SAML SSO. Source: SAML SSO configuration.
Automation: ClickOps only — Notion exposes no write interface for this setting: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
1.3 Configure SCIM Provisioning
Profile Level: L2 (Walk)
| Framework | Control |
|---|---|
| CIS Controls | 5.3 |
| NIST 800-53 | AC-2 |
Description
Configure SCIM for automated user lifecycle management.
Rationale
Why This Matters:
- Automated provisioning and deprovisioning grants access on hire and revokes it the moment a user is removed from the IdP
- Manual offboarding is slow and error-prone, leaving orphaned accounts that retain standing access to sensitive workspace content
- SCIM keeps Notion group and role membership synchronized with your directory, preventing privilege drift over time
- Suppressing SCIM invite emails lets security control rollout communication rather than auto-notifying every provisioned user
Attack Prevented: Orphaned-account access, privilege creep, insider misuse after offboarding
ClickOps Implementation
Step 1: Enable SCIM
- Navigate to: Settings → Identity → SCIM provisioning (workspace), or the workspace switcher → Manage organization (Enterprise organization owners)
- Open SCIM tokens — below Enterprise the console reads “Upgrade to generate a token to configure SCIM”
- Generate SCIM API token
Step 2: Configure IdP SCIM
- Add Notion SCIM integration in IdP
- Enter SCIM endpoint URL
- Enter API token
Step 3: Configure Provisioning Settings
- Turn on Suppress invite emails from SCIM provisioning
- Control internal rollout communication
- Test user synchronization
- Supported IdPs include Okta, OneLogin, Rippling, and custom SCIM applications
Step 4: Manage Token Hygiene
- Generate a separate SCIM API token for each workspace you manage via SCIM — tokens are workspace-scoped, not organization-wide
- Owners can revoke a token at any time; revocation disables the SCIM integration and all provisioning depending on it until an active token replaces it
- Store tokens as secrets in your existing secret manager, never in IdP notes or runbooks in plaintext
Replace SCIM tokens BEFORE de-provisioning the admin who created them. A token created by a workspace owner is automatically revoked when that owner leaves or changes role — Notion then notifies the remaining owners to replace it. If you offboard an admin first, provisioning breaks silently at exactly the moment you are relying on it to remove access. Sequence the change: issue a replacement token, repoint the IdP, verify a test sync, then de-provision the admin. Source: Provision users and groups with SCIM.
Validation & Testing
Deactivate a test user in the IdP and confirm the Notion account is deprovisioned. After any admin change, run a sync and confirm it still succeeds rather than assuming it does.
Automation: ClickOps only — the SCIM API provisions users and groups once configured, but enabling SCIM and generating its token is console-only: “Only Enterprise Plan organization owners can generate and view SCIM API tokens” (Provision users and groups with SCIM, 2026-10-04).
2. Organization Security
2.1 Configure Workspace Access
Profile Level: L1 (Crawl)
| Framework | Control |
|---|---|
| CIS Controls | 5.4 |
| NIST 800-53 | AC-6 |
Description
Control who can access workspaces and create accounts.
Rationale
Why This Matters:
- Restricting allowed email domains keeps workspace membership limited to corporate identities and blocks personal or attacker-controlled addresses
- Disabling automatic account creation prevents anyone who passes SSO from self-provisioning into the workspace without explicit approval
- Uncontrolled joining lets unauthorized or stale accounts accumulate, expanding who can read internal pages and databases
- Regular membership review enforces least privilege and removes users who no longer need access
Attack Prevented: Unauthorized account creation, rogue workspace access, membership sprawl
ClickOps Implementation
Step 1: Configure Allowed Email Domains
- Navigate to: Settings → General
- Configure Allowed email domains
- Restrict to corporate domains only
Step 2: Disable Automatic Account Creation
- Navigate to: Settings → Identity → SAML single sign-on (SSO) and turn off Automatic account creation (the toggle is only active once SAML SSO is enabled on a verified domain)
- Prevents users from creating accounts through SSO
- Requires explicit provisioning
Step 3: Configure Membership
- Navigate to: Settings → People and review Members and Guests
- Remove unauthorized users
- Apply least privilege
Code Implementation
The pack below audits membership through the public API. On the Enterprise Plan, the SCIM API is also a write surface for Step 3: DELETE /scim/v2/Users/<id> removes a member from the workspace (Provision users and groups with SCIM, 2026-10-04).
Code Pack: API Script
NOTION_VERSION="2026-03-11"
cursor=""
calls=0
while :; do
url="https://api.notion.com/v1/users?page_size=100"
[ -n "${cursor}" ] && url="${url}&start_cursor=${cursor}"
code=$(curl -sS -o "${BODY_FILE}" -w '%{http_code}' "${url}" \
-H "Authorization: Bearer ${NOTION_TOKEN}" \
-H "Notion-Version: ${NOTION_VERSION}") || code="000"
if [ "${code}" != "200" ]; then
echo "PRECONDITION: GET /v1/users returned HTTP ${code}: $(jq -r '.code // "no body"' "${BODY_FILE}" 2>/dev/null || echo unreadable)" >&2
echo " 401 = invalid token; 403 = integration lacks the user-information capability." >&2
exit 2
fi
jq -c '.results[]' "${BODY_FILE}" >> "${USERS_FILE}"
calls=$((calls + 1))
[ "$(jq -r '.has_more' "${BODY_FILE}")" = "true" ] || break
cursor=$(jq -r '.next_cursor' "${BODY_FILE}")
[ "${calls}" -lt 500 ] || { echo "PRECONDITION: pagination runaway guard hit" >&2; exit 2; }
done
report=$(jq -s --arg allowed "${ALLOWED_EMAIL_DOMAINS}" '
($allowed | ascii_downcase | split(",") | map(gsub("^\\s+|\\s+$"; "")) | map(select(. != ""))) as $ok
| {
people: [ .[] | select(.type == "person") ],
bots: [ .[] | select(.type == "bot") | (.name // "(unnamed)") ]
}
| .flagged = [ .people[]
| ((.person.email // "") | ascii_downcase) as $e
| (if ($e | contains("@")) then ($e | split("@") | last) else "" end) as $d
| select(($ok | index($d)) == null)
| "\(.name // "(unnamed)") <\(if $e == "" then "email not visible" else $e end)>" ]
' "${USERS_FILE}")
n_people=$(jq '.people | length' <<<"${report}")
n_bots=$(jq '.bots | length' <<<"${report}")
n_flagged=$(jq '.flagged | length' <<<"${report}")
echo "${n_people} person user(s), ${n_bots} bot/integration user(s)"
jq -r '.bots[] | " bot: \(.)"' <<<"${report}"
if [ "${n_people}" -eq 0 ]; then
echo "INCONCLUSIVE: the API returned zero person users — nothing was audited" >&2
exit 2
fi
if [ "${n_flagged}" -gt 0 ]; then
echo "WARN: ${n_flagged} member(s) outside allowed email domains:"
jq -r '.flagged[] | " \(.)"' <<<"${report}"
echo "Remove unauthorized members and restrict allowed email domains (control 2.1)."
exit 1
fi
echo "PASS: all ${n_people} person user(s) are inside ${ALLOWED_EMAIL_DOMAINS}"
2.2 Configure Team Spaces
Profile Level: L2 (Walk)
| Framework | Control |
|---|---|
| CIS Controls | 5.4 |
| NIST 800-53 | AC-6 |
Description
Organize content using team spaces for access control.
Rationale
Why This Matters:
- Team spaces partition content so each team sees only the pages relevant to its function rather than the entire workspace
- Segmentation limits the blast radius of a compromised account to a single team space instead of all organizational knowledge
- Per-space sharing and export restrictions let sensitive teams such as legal, finance, and HR apply tighter controls than the default
- Without segmentation, broad default membership exposes confidential content to every member by accident
Attack Prevented: Lateral movement, over-broad data exposure, accidental cross-team disclosure
ClickOps Implementation
Step 1: Create Team Spaces
- Navigate to: Settings → Teamspaces; turn on Limit teamspace creation to workspace owners and review Default teamspaces
- Organize teamspaces by team or function
- Limit membership appropriately
Step 2: Configure Team Space Security
- Open each teamspace’s ··· → Teamspace settings → Security
- Set Who can invite or remove teamspace members and Who can edit teamspace sidebar
- On Enterprise, also set Disable publishing sites, forms, and public links, Disable guests, and Disable export per teamspace — below Enterprise these read “Upgrade to Enterprise”
Automation: ClickOps only — Notion exposes no write interface for teamspace settings: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
2.3 Limit Admin Access
Profile Level: L1 (Crawl)
| Framework | Control |
|---|---|
| CIS Controls | 5.4 |
| NIST 800-53 | AC-6(1) |
Description
Minimize and protect workspace owner accounts.
Rationale
Why This Matters:
- Workspace owners hold the highest privilege — they control SSO, security settings, membership, and export policy for the entire org
- Minimizing owners to a small, documented set reduces the number of high-value accounts an attacker can target for full takeover
- Excess admin accounts are often dormant and unmonitored, making them ideal footholds for privilege escalation
- Assigning regular users the member role enforces least privilege and keeps administrative power scoped to those who need it
Attack Prevented: Admin account takeover, privilege escalation, unauthorized configuration changes
ClickOps Implementation
Step 1: Inventory Workspace Owners
- Navigate to: Settings → People
- Review workspace owners
- Document all administrators
Step 2: Apply Least Privilege
- Limit workspace owners to 2-3 users
- Use member roles for regular users
- Remove unnecessary admin access
Code Implementation
Workspace roles are not in Notion’s public REST API (the user object from GET /v1/users carries no role), but the SCIM API reads and writes them through the role attribute of the Notion user-schema extension (owner, membership_admin, member). SCIM is Enterprise-only, and only an organization owner can generate its token (Provision users and groups with SCIM, 2026-10-04). The pack below reads that attribute to inventory owners; it changes nothing.
Code Pack: API Script
SCIM_BASE="https://api.notion.com/scim/v2"
EXT="urn:ietf:params:scim:schemas:extension:notion:2.0:User"
start=1
calls=0
while :; do
code=$(curl -sS -o "${BODY_FILE}" -w '%{http_code}' \
"${SCIM_BASE}/Users?startIndex=${start}&count=100" \
-H "Authorization: Bearer ${NOTION_SCIM_TOKEN}" \
-H "Accept: application/scim+json") || code="000"
if [ "${code}" != "200" ]; then
echo "PRECONDITION: GET /scim/v2/Users returned HTTP ${code}" >&2
echo " 401 = invalid or revoked SCIM token; 403/404 = workspace not on the Enterprise Plan or SCIM not set up." >&2
exit 2
fi
if ! jq -e '(.Resources | type == "array") and (.totalResults | type == "number")' "${BODY_FILE}" >/dev/null 2>&1; then
echo "PRECONDITION: response is not a SCIM ListResponse (no Resources array / totalResults)" >&2
exit 2
fi
page=$(jq '.Resources | length' "${BODY_FILE}")
jq -c '.Resources[]' "${BODY_FILE}" >> "${USERS_FILE}"
total=$(jq '.totalResults' "${BODY_FILE}")
calls=$((calls + 1))
start=$((start + page))
[ "${page}" -gt 0 ] && [ "$((start - 1))" -lt "${total}" ] || break
[ "${calls}" -lt 500 ] || { echo "PRECONDITION: pagination runaway guard hit" >&2; exit 2; }
done
report=$(jq -s --arg ext "${EXT}" '
[ .[] | select(.active != false) ] as $active
| {
n_active: ($active | length),
no_role: [ $active[] | select((.[$ext].role // "") == "") | (.userName // .id) ],
owners: [ $active[] | select(.[$ext].role == "owner") | "\(.displayName // .name.formatted // "(unnamed)") <\(.userName // .id)>" ],
admins: [ $active[] | select(.[$ext].role == "membership_admin") | (.userName // .id) ]
}
' "${USERS_FILE}")
n_active=$(jq '.n_active' <<<"${report}")
n_no_role=$(jq '.no_role | length' <<<"${report}")
n_owners=$(jq '.owners | length' <<<"${report}")
n_admins=$(jq '.admins | length' <<<"${report}")
echo "${n_active} active member(s): ${n_owners} workspace owner(s), ${n_admins} membership admin(s)"
jq -r '.owners[] | " owner: \(.)"' <<<"${report}"
if [ "${n_active}" -eq 0 ]; then
echo "INCONCLUSIVE: SCIM returned zero active members — nothing was audited" >&2
exit 2
fi
if [ "${n_no_role}" -gt 0 ]; then
echo "INCONCLUSIVE: ${n_no_role} active member(s) came back without the ${EXT} role attribute — the owner count cannot be trusted" >&2
exit 2
fi
if [ "${n_owners}" -eq 0 ]; then
echo "INCONCLUSIVE: no workspace owner returned — every workspace has at least one, so the listing is incomplete" >&2
exit 2
fi
if [ "${n_owners}" -gt "${MAX_OWNERS}" ]; then
echo "WARN: ${n_owners} workspace owners exceeds MAX_OWNERS=${MAX_OWNERS}."
echo "Demote owners who do not need full administrative control to member (control 2.3)."
exit 1
fi
echo "PASS: ${n_owners} workspace owner(s), within MAX_OWNERS=${MAX_OWNERS}"
3. Data Protection
3.1 Configure Sharing Controls
Profile Level: L1 (Crawl)
| Framework | Control |
|---|---|
| CIS Controls | 3.3 |
| NIST 800-53 | AC-3 |
Description
Control how content can be shared internally and externally.
Rationale
Why This Matters:
- Default “Anyone with link” and public-page settings can silently expose internal content to the open internet and search engines
- Constraining guest permissions and link sharing ensures content is shared only with explicitly authorized people
- Auditing and disabling unneeded public pages closes accidental data leaks that bypass authentication entirely
- Notion pages frequently contain customer data, credentials, and strategy docs that must never be reachable by an anonymous link
Attack Prevented: Data leakage, unauthorized external access, public exposure of confidential pages
ClickOps Implementation
Step 1: Configure Guest Access
- Navigate to: Settings → Security → Members & guests → Who can invite guests to pages
- Restrict guest invitations — below Enterprise the console reads “Upgrade to disable the ability for members to invite guests to pages”
- Limit guest capabilities
Step 1b: Turn Guests Off Entirely (Enterprise)
- Enterprise workspace owners can enable Disable guests, which blocks external invitations outright — the cleanest control where external collaboration is not a business requirement
- Where guests are occasionally needed, owners can instead allow members to send guest invite requests, converting ad-hoc external sharing into a reviewable request rather than a silent grant
- Source: Notion Enterprise security provisions
Step 2: Configure Public Pages
- Audit at Settings → Public pages (Notion Sites, Public forms, Anyone with the link, Shared AI chats, Domains)
- Unpublish anything not deliberately public
- On Enterprise, turn on Settings → Security → Disable public forms, page links, and Notion Sites
Step 3: Configure Link Sharing
- Set default sharing permissions
- Restrict “Anyone with link” access
- Require explicit permissions
Code Implementation
Code Pack: API Script
NOTION_VERSION="2026-03-11"
cursor=""
calls=0
while :; do
payload=$(jq -nc --arg c "${cursor}" \
'{filter: {property: "object", value: "page"}, page_size: 100}
+ (if $c == "" then {} else {start_cursor: $c} end)')
code=$(curl -sS -o "${BODY_FILE}" -w '%{http_code}' "https://api.notion.com/v1/search" \
-H "Authorization: Bearer ${NOTION_TOKEN}" \
-H "Notion-Version: ${NOTION_VERSION}" \
-H "Content-Type: application/json" \
-d "${payload}") || code="000"
if [ "${code}" != "200" ]; then
echo "PRECONDITION: POST /v1/search returned HTTP ${code}: $(jq -r '.code // "no body"' "${BODY_FILE}" 2>/dev/null || echo unreadable)" >&2
exit 2
fi
jq -c '.results[]' "${BODY_FILE}" >> "${PAGES_FILE}"
calls=$((calls + 1))
[ "$(jq -r '.has_more' "${BODY_FILE}")" = "true" ] || break
cursor=$(jq -r '.next_cursor' "${BODY_FILE}")
[ "${calls}" -lt 500 ] || { echo "PRECONDITION: pagination runaway guard hit" >&2; exit 2; }
done
scanned=$(jq -s 'length' "${PAGES_FILE}")
public=$(jq -s '[ .[] | select(.public_url != null and .public_url != "") ]' "${PAGES_FILE}")
n_public=$(jq 'length' <<<"${public}")
echo "scanned ${scanned} page(s) shared with this integration"
if [ "${scanned}" -eq 0 ]; then
echo "INCONCLUSIVE: 0 pages are shared with this integration — share the content to audit (page ··· → Connections) and re-run" >&2
exit 2
fi
if [ "${n_public}" -gt 0 ]; then
echo "WARN: ${n_public} page(s) reachable by anyone on the internet:"
jq -r '.[] | " \(.id)\tlast_edited=\(.last_edited_time)\t\(.public_url)"' <<<"${public}"
echo "Unpublish any page not deliberately public (control 3.1)."
exit 1
fi
echo "PASS: none of the ${scanned} scanned page(s) is published to the web"
3.2 Disable Moving and Duplicating Pages to Other Workspaces
Profile Level: L2 (Walk)
| Framework | Control |
|---|---|
| CIS Controls | 3.1 |
| NIST 800-53 | AC-3 |
Description
On Enterprise, turn on Disable duplicating pages to other workspaces so members cannot relocate or copy pages into personal or external workspaces.
Rationale
Why This Matters:
- Page duplication to external or personal workspaces lets members copy sensitive content outside organizational control
- Move to is the path most policies miss: moving a page relocates the original rather than copying it, so a duplication-only control leaves the higher-impact action open
- Disabling both removes a low-friction exfiltration path that bypasses sharing and export restrictions
- Content moved or copied out leaves the source workspace’s governance, making the loss hard to detect and impossible to revoke
Attack Prevented: Data exfiltration, content theft, unauthorized data movement out of the workspace
Correction (2026-10): the console label is “Disable duplicating pages to other workspaces,” but the setting covers both actions. Its description in Settings → Security reads “prevent users from duplicating pages to other workspaces via Move To or Duplicate To” — so the label names only duplicating, while the control also blocks Move to. The 2026-08 revision of this guide gave the name as “Disable moving or duplicating pages to other workspaces,” which is not the label the console shows. Source: Notion Enterprise security provisions.
ClickOps Implementation
Step 1: Enable the Control
- Navigate to: Settings → Security (Enterprise — below Enterprise the toggle reads “Upgrade”)
- Turn on Disable duplicating pages to other workspaces
- This blocks both the copy path and the move path out of the workspace
Step 2: Review Exceptions
- Document any business need for moving or duplicating content externally
- Consider enabling per team space if needed
- Monitor for policy violations in the audit log (4.1)
Validation & Testing
As a test member, open a page’s ••• menu and confirm both Duplicate to and Move to offer no destination outside the workspace.
Automation: ClickOps only — Notion exposes no write interface for this setting: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
3.3 Configure Export Controls
Profile Level: L2 (Walk)
| Framework | Control |
|---|---|
| CIS Controls | 3.1 |
| NIST 800-53 | AC-3 |
Description
Control ability to export content from Notion.
Rationale
Why This Matters:
- Bulk export to PDF, HTML, or Markdown can extract entire workspaces in a single action, a classic mass-exfiltration vector
- Disabling export by default and enabling it only where needed limits who can pull content out of Notion
- Reviewing export logs surfaces unusual or bulk activity that may signal a compromised account or departing insider
- Without export controls, a single compromised member can offload large volumes of intellectual property undetected
Attack Prevented: Mass data exfiltration, insider data theft, intellectual property loss
Prerequisites
- Notion Enterprise plan (below Enterprise the toggle reads “Upgrade”)
- Workspace owner role
ClickOps Implementation
Step 1: Configure Export Settings
- Navigate to: Settings → Security
- Turn on Disable exports
- Per teamspace: ··· → Teamspace settings → Security → Disable export, keeping export available only in teamspaces that need it
Step 2: Audit Export Activity
- Review export events in the audit log (4.1)
- Monitor for unusual patterns
- Investigate bulk exports
Automation: ClickOps only — Notion exposes no write interface for this setting: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
3.4 Connect a Data Loss Prevention Provider
Profile Level: L3 (Run)
| Framework | Control |
|---|---|
| CIS Controls | 3.13 |
| NIST 800-53 | SI-4, AC-4, SC-7(10) |
Description
On Enterprise, connect a supported DLP provider so page and file content is scanned automatically for sensitive data — PII, PHI, and credentials — with detection and remediation handled outside Notion’s own permission model. Notion documents Nightfall AI as available, with Polymer listed as coming soon.
Rationale
Why This Matters:
- Permission and sharing controls govern who can reach a page; they say nothing about what someone pasted into it — secrets and regulated data land in Notion pages routinely
- Automated scanning finds credentials committed into runbooks and PII pasted into project pages long before an audit or a breach would
- Automated remediation shortens exposure time compared with a quarterly manual review of a workspace that grows daily
- DLP is the control that makes broad internal sharing survivable: it addresses the content risk that team-space segmentation (2.2) does not
Attack Prevented: Credential exposure in workspace content, regulated-data (PII/PHI) sprawl, undetected sensitive-data accumulation, secondary compromise from secrets stored in documentation
Prerequisites
- Notion Enterprise plan
- A subscription with the DLP provider
- Workspace owner / organization owner role
ClickOps Implementation
Step 1: Select and Connect the Provider
- Confirm which supported provider your organization uses — Nightfall AI is the currently available integration
- As an organization owner, connect the provider from Settings → Connections → Discover → DLP → Nightfall AI
- Authorize the connection with the scope the provider requires
Step 2: Define Detection and Remediation Policy
- Configure the detectors that match your obligations (PII, PHI, payment data, API keys and other credentials)
- Decide the remediation action per detector — alert, redact, or restrict — rather than accepting the provider default everywhere
- Route alerts to the same queue that handles your other DLP findings, not to a Notion-only inbox
Validation & Testing
Paste a synthetic detector-triggering string (a test credential pattern) into a scratch page and confirm the provider raises a finding and applies the configured remediation. Source: Notion Enterprise security provisions.
Automation: ClickOps only — Notion exposes no write interface for DLP provider connections: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
3.5 Govern Notion AI Settings
Profile Level: L2 (Walk)
| Framework | Control |
|---|---|
| CIS Controls | 3.3 |
| NIST 800-53 | AC-3, CM-7, SC-7 |
Description
Review and set the workspace-level Notion AI controls under Settings → Notion AI: whether workspace data is shared to improve Notion AI, which AI Connectors to third-party apps are enabled, whether AI may search the web or drive a browser, whether agents may skip approvals, which models members may use, and image generation — plus AI Meeting Notes audio and transcript retention under Settings → Meeting notes.
Rationale
Why This Matters:
- AI features read workspace content to answer; the data-sharing toggle determines whether that content also feeds product improvement, which is a procurement and privacy decision, not a user preference
- AI Connectors extend Notion AI’s reach into other systems (Slack, Google Drive and similar), so each connector widens the blast radius of a compromised Notion account beyond Notion
- Web search and the agent web browser let AI send workspace-derived context outbound; keeping Enable ‘Skip all approvals’ off is the control that keeps a human in that loop
- AI Meeting Notes generate audio recordings and transcripts — durable, highly sensitive artifacts whose retention must be set deliberately rather than left at default
- Some models must be enabled by a workspace admin before members can select them, so the model roster is an admin decision that should follow your third-party AI review
Attack Prevented: Unintended workspace-content sharing for model improvement, outbound data leakage via AI web requests, over-broad AI reach into connected SaaS, indefinite retention of meeting audio and transcripts, use of models outside the approved roster
Prerequisites
- Workspace owner role
- Business or Enterprise plan for image generation
ClickOps Implementation
Step 1: Set the Data-Sharing Posture
- Navigate to: Settings → Notion AI
- Set Share data to improve Notion AI according to your data-handling policy — decide this explicitly rather than inheriting the default
Step 2: Constrain External Reach
- Review Settings → Notion AI → AI connectors and remove connectors to third-party apps without a business justification
- Set Enable web search for workspace deliberately
- Set Enable web browser for computer deliberately and keep Enable ‘Skip all approvals’ off so agents cannot act without approval
Step 3: Govern Models and Generation
- Review Allowed models for Notion Agent, Allowed models for Custom Agents, and Default model for Custom Agents — certain models require workspace-admin enablement before members can select them
- Set Enable image generation (available on Business and Enterprise)
- Review agent personalization settings (name, appearance, custom instructions) as part of the same review
Step 4: Bound AI Meeting Notes Retention
- Navigate to: Settings → Meeting notes
- Set Automatic transcript deletion (Enterprise — the default is Never), Store audio locally, and Enforce consent for all workspace members
- Align the retention window with your recording and records-retention policy, not with the platform default
Validation & Testing
Confirm Enable ‘Skip all approvals’ reads off, then as a test member trigger an agent action that writes and confirm the approval prompt appears; then create an AI meeting note and confirm the audio and transcript are removed on the configured schedule. Sources: Notion AI FAQs, Notion Agent.
Automation: ClickOps only — Notion exposes no write interface for Notion AI workspace settings: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
3.6 Govern Agent and MCP Connections
Profile Level: L2 (Walk)
| Framework | Control |
|---|---|
| CIS Controls | 3.3, 6.8 |
| NIST 800-53 | AC-3, AC-6, CM-7, SA-9 |
Description
Restrict which AI apps and MCP clients members may connect to the workspace, maintain the approved list, and keep human confirmation on non-read-only tools. Notion operates a remote MCP server it hosts, and agents acting through it carry the connecting user’s full permissions.
Rationale
Why This Matters:
- Notion is explicit that an agent’s reach equals the user’s: “Notion Agent has the same permissions you do. If you can’t view or edit specific content, your Agent can’t either” — and for MCP, “MCP tools act with your full Notion permissions—they can access everything you can access.” An over-permissioned user becomes an over-permissioned agent
- Because agents inherit permissions verbatim, least privilege at the user level (2.3) is what actually bounds agent capability; there is no separate agent permission ceiling to fall back on
- Without an approved list, any member can wire an arbitrary external AI client into the workspace, creating an unreviewed egress path for everything that member can read
- Notion states that custom MCP servers have not been reviewed by Notion — a workspace owner enabling one is accepting third-party risk on the organization’s behalf
- Prompt-injected content in a page can steer an agent; keeping confirmation on non-read-only tools ensures an injected instruction cannot silently write, delete, or share
Attack Prevented: Data exfiltration through unapproved AI clients and MCP servers, prompt-injection-driven agent actions, over-broad agent access inherited from over-privileged users, unreviewed third-party tooling reaching workspace content
Prerequisites
- Enterprise plan for the approved-list restriction
- Workspace owner role
ClickOps Implementation
Step 1: Restrict Which AI Apps Can Connect (Enterprise)
- Navigate to: Settings → Notion MCP → Manage workspace clients
- Set Which clients members can connect to an approved list instead of All MCP clients (Enterprise — below it the console reads “Upgrade to control what workspace members can connect”) — Notion blocks every call from any AI app or MCP client not on the list
- Use Disconnect all users (under Disconnect all connections to Notion MCP) to revoke MCP connections workspace-wide during an incident
- Under Settings → Connections → Manage, leave Enable custom MCP servers off unless reviewed, and review external agents at Settings → Notion AI → Agents → Manage external agents
Step 2: Keep Confirmation On
- Keep Settings → Notion AI → Enable ‘Skip all approvals’ turned off — Notion requests human confirmation for tool calls on non-read-only tools only while approvals are not skipped
- Where an agent only needs to read, enable only read-only tools for it
Step 3: Scope Each Agent Narrowly
- Create agents for specific purposes rather than one agent with access to everything, and avoid granting unnecessary page or database access
- Review each agent’s enabled tools and resources after adding a connection, and disable what it does not need
- Add only servers you trust; research the provider before integrating, and treat custom MCP servers as unreviewed by Notion
Validation & Testing
As a non-owner member, attempt to connect an AI client that is not on the approved list and confirm the connection is blocked. Then exercise a non-read-only tool through an approved agent and confirm the confirmation prompt appears. Sources: Notion MCP, Security best practices for agent connections, Notion MCP (developer docs).
Automation: ClickOps only — Notion exposes no write interface for MCP client governance; the MCP server acts on content with the connecting user’s permissions and has no admin settings tools (Notion MCP, 2026-10-04).
3.7 Manage API Connections and Integrations
Profile Level: L2 (Walk)
| Framework | Control |
|---|---|
| CIS Controls | 3.3, 6.8 |
| NIST 800-53 | AC-3, CM-7, SA-9 |
Description
On Enterprise, restrict which API connections members may install, maintain an approved connections list, review who has each connection installed, and control which pages a connection can reach and who may connect or disconnect it.
Rationale
Why This Matters:
- An installed connection holds a durable token to workspace content and keeps reading it long after the person who installed it stops paying attention
- An approved connections list converts integration adoption from a per-member decision into a reviewed organizational one
- Being able to see every member who has a given connection installed is what makes a vendor-compromise response tractable — you can enumerate and disconnect rather than guess
- Page-level access control keeps a connection scoped to the content it needs instead of the whole workspace
- Deciding whether all members or only workspace owners may manage a connection’s page access prevents quiet scope expansion after approval
Attack Prevented: Supply-chain compromise via third-party integrations, shadow-IT connections, over-broad integration access to workspace content, unrevoked integration access after vendor incidents
Prerequisites
- Notion Enterprise plan for the restriction and approved list
- Workspace owner role
ClickOps Implementation
Step 1: Restrict and Curate
- Navigate to: Settings → Connections → Manage
- Set Limit which connections members can install and build the approved connections list (Enterprise — below it the console reads “Upgrade to control what workspace members can connect”)
- Set Limit who can create internal connections and Limit who can create personal access tokens (PATs) to Workspace owners only (available below Enterprise)
Step 2: Review Installations
- For each connection, view all members who have it installed
- Disconnect members from connections that are unused, unapproved, or belong to a vendor with an open security issue
Step 3: Scope Page Access
- For each connection, select the specific pages it may access
- Choose whether all workspace owners and members or only Workspace owners can manage that connection’s page access — prefer owners-only for connections touching sensitive content
Validation & Testing
As a member, attempt to install a connection outside the approved list and confirm it is blocked. Then confirm an approved connection can only reach the pages you selected. Source: Add and manage connections with the API.
Automation: ClickOps only — Notion exposes no API to list or restrict workspace connections: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
4. Monitoring & Compliance
4.1 Configure Audit Logging
Profile Level: L1 (Crawl)
| Framework | Control |
|---|---|
| CIS Controls | 8.2 |
| NIST 800-53 | AU-2 |
Description
Enable and monitor the Notion audit log — available to organization owners on the Enterprise plan — and stream its events to a SIEM via custom webhook or a supported partner integration.
Rationale
Why This Matters:
- Audit logs provide the authoritative record of who did what and when across the organization’s Notion activity
- Monitoring provisioning, permission changes, exports, and SSO configuration changes enables timely detection of misuse
- The log now includes a dedicated Workers event family covering agent and worker creation, deployment, runs, and secrets — the only telemetry that shows what automated actors did on your behalf (see 3.6)
- Exporting audit events to a SIEM correlates Notion activity with the rest of the security stack for centralized alerting, and preserves history beyond Notion’s retention window
Attack Prevented: Undetected breaches, insider misuse, configuration tampering without accountability, unmonitored agent and worker activity
Correction (2026-10): the audit log is not under Analytics, and its history has two hard boundaries. The workspace audit log is at Settings → Audit log (listed in the Admin group of the Settings sidebar); the organization audit log is at the workspace switcher → Manage organization → Data & Compliance → Audit log — earlier revisions of this guide pointed at “Organization Settings → Analytics.” Two limits matter operationally: history is retained up to 365 days, and events are only recorded from the date the organization upgraded to Enterprise — there is no backfill of prior activity. Exports also capture data up to roughly two hours before the request. Treat regular export or streaming as the mechanism that preserves anything you need beyond a year. Source: Audit log.
Prerequisites
- Notion Enterprise plan
- Organization owner role
ClickOps Implementation
Step 1: Access Audit Logs
- Workspace: Settings → Audit log (Admin group of the sidebar). Organization: workspace switcher → Manage organization → Data & Compliance → Audit log
- Filter by date, person or agent, event type, or related activity
- Export as CSV (filters apply to the export) on a schedule if you are not streaming
Step 2: Monitor Key Events
- Page events and teamspace events
- Workspace events — including SSO and security configuration changes
- Account events — provisioning, deprovisioning, and role changes
- Workers events — agent/worker creation, deployment, runs, and secrets
- Form events and data source events
- Content exports and sharing changes
Step 3: Stream to a SIEM
- Configure event streaming to your SIEM from Settings → Connections → Discover → SIEM — Notion publishes partner guidance for Splunk, Sumo Logic, Panther, and Datadog
- For anything else, use custom webhook streaming: one webhook endpoint per workspace, JSON payloads containing metadata only (never page content), with up to seven retry attempts over roughly 24 hours
- Note that syslog is not supported — webhook delivery is the only streaming transport
- Alert on delivery failure: with a single endpoint per workspace and a bounded retry window, a broken receiver loses events permanently
Validation & Testing
Trigger a known auditable action (a permission change, then an export) and confirm it appears in the audit log and arrives at the SIEM endpoint within your expected latency. Verify the retry behavior by taking the receiver offline briefly and confirming redelivery.
Automation: ClickOps only — Notion exposes no REST endpoint for audit-log configuration or retrieval; events leave Notion only through webhook/SIEM streaming (“No syslog support: Webhooks only”) (Audit log, 2026-10-04).
4.2 Configure Analytics
Profile Level: L1 (Crawl)
| Framework | Control |
|---|---|
| CIS Controls | 8.2 |
| NIST 800-53 | CA-7 |
Description
Use analytics to monitor workspace activity.
Rationale
Why This Matters:
- Workspace analytics reveal usage patterns that establish a behavioral baseline for normal activity
- Tracking guest access and sharing trends helps spot anomalous behavior such as sudden spikes in external sharing
- Reviewing member activity surfaces dormant or compromised accounts that deviate from expected patterns
- Analytics complement audit logs by turning raw events into trends that drive proactive security review
Attack Prevented: Undetected anomalous activity, unmonitored guest and sharing abuse, slow incident detection
ClickOps Implementation
Step 1: Access Analytics
- Navigate to: Settings → Analytics (workspace analytics — Enterprise; below it the page reads “Upgrade to the Enterprise plan to gain visibility into workspace-level engagement, adoption trends, and AI usage”); on lower plans turn on Settings → General → Save and display page view analytics for page-level views
- Review workspace usage
- Monitor member activity
Step 2: Review Security Metrics
- Track guest access patterns
- Monitor sharing activity
- Identify unusual behavior
Automation: ClickOps only — Notion exposes no analytics API: Notion’s public API covers blocks, pages, databases, data sources, comments, views, file uploads, search, users, custom emojis and agents, and no workspace or organization settings (API reference, 2026-10-04).
5. Compliance Quick Reference
SOC 2 Trust Services Criteria Mapping
| Control ID | Notion Control | Guide Section |
|---|---|---|
| CC6.1 | SSO/SAML | 1.1 |
| CC6.2 | Workspace permissions | 2.3 |
| CC6.6 | Access controls | 2.1 |
| CC6.7 | Export controls | 3.3 |
| CC7.2 | Audit logging | 4.1 |
NIST 800-53 Rev 5 Mapping
| Control | Notion Control | Guide Section |
|---|---|---|
| IA-2 | SSO | 1.1 |
| AC-2 | SCIM provisioning | 1.3 |
| AC-3 | Sharing controls | 3.1 |
| AC-6 | Least privilege | 2.3 |
| AU-2 | Audit logging | 4.1 |
Appendix A: Plan Compatibility
| Feature | Free | Plus | Business | Enterprise |
|---|---|---|---|---|
| SAML SSO (1.1) | ❌ | ❌ | ✅ | ✅ |
| Require SAML SSO authorization for workspace access (1.2) | ❌ | ❌ | ❌ | ✅ |
| SCIM (1.3) | ❌ | ❌ | ❌ | ✅ |
| Domain Verification | ❌ | ❌ | ✅ | ✅ |
| Export Controls (3.3) | ❌ | ❌ | ❌ | ✅ |
| Disable guests / guest invite requests (3.1) | ❌ | ❌ | ❌ | ✅ |
| Disable public forms, page links, and Notion Sites (3.1) | ❌ | ❌ | ❌ | ✅ |
| Teamspace page security — publishing, guests, export (2.2) | ❌ | ❌ | ❌ | ✅ |
| Disable duplicating pages to other workspaces (3.2) | ❌ | ❌ | ❌ | ✅ |
| DLP provider connection (3.4) | ❌ | ❌ | ❌ | ✅ |
| Notion AI image generation (3.5) | ❌ | ❌ | ✅ | ✅ |
| Restrict AI apps to approved list (3.6) | ❌ | ❌ | ❌ | ✅ |
| Restrict connections / approved connections list (3.7) | ❌ | ❌ | ❌ | ✅ |
| Audit Logs + SIEM streaming (4.1) | ❌ | ❌ | ❌ | ✅ |
| Workspace analytics (4.2) | ❌ | ❌ | ❌ | ✅ |
Note: Audit log events are recorded only from the date the organization upgraded to Enterprise, and history is retained up to 365 days (see 4.1).
Appendix B: References
Official Notion Documentation:
- Help Center
- Security Practices
- Enterprise Security Provisions
- SAML SSO Configuration
- Provision Users with SCIM
- Audit log
- Add and manage connections with the API
- Notion MCP
- Security best practices for agent connections
- Notion AI FAQs
- Notion Agent
- Managing Organization in Notion
API Documentation:
Compliance Frameworks:
- HIPAA compliance and configuration guidance — BAA eligibility requires the Enterprise plan; Notion may not be used to communicate with patients, plan members, or their families or employers
Security Incidents:
- No major breaches of Notion infrastructure identified. In 2025, security researchers disclosed prompt injection risks in Notion AI agents that could enable data exfiltration via crafted workspace content (CVE-2024-23745 also affected Notion Web Clipper 1.0.3). These are configuration and feature-level risks, not infrastructure compromises.
Changelog
| Date | Version | Maturity | Changes | Author |
|---|---|---|---|---|
| 2026-10-04 | 0.2.2 | ai-drafted · ai-validated | validate-hth-guide run against a live Notion workspace (Business Trial): Settings walked read-only in a real browser across all 15 controls; 1 surface came back VERIFIED-LIVE (2.3 ClickOps, Step 1 only — Settings → People owner inventory; the Step 2 role selector was not opened), every other surface was corrected to the live console, is plan-gated (Enterprise), or awaits a credential. Corrected console paths and labels in 1.1, 1.2, 1.3, 2.1, 2.2, 3.1, 3.2 (label is “Disable duplicating pages to other workspaces”), 3.3 (“Disable exports”), 3.4, 3.5 (removed the nonexistent “Require confirmation for web requests”; Meeting notes retention moved to Settings → Meeting notes), 3.6 (Settings → Notion MCP → Manage workspace clients; “Enable ‘Skip all approvals’”), 3.7, 4.1 (Settings → Audit log; org path Manage organization → Data & Compliance) and 4.2; Appendix A now marks 2.2 teamspace security, 3.1 public-link disable, 3.2, 3.3 and 4.2 analytics Enterprise-only as the console gates them; evidenced **Automation:** ClickOps only verdicts added to 12 pack-less controls; new read-only SCIM pack 2.03 inventories workspace owners through the SCIM role attribute (Enterprise; Bearer auth per Notion’s IdP setup article; not run against this Business Trial); packs 2.01/3.01 rewritten from Python to bash+curl (api/ type) and made fail-closed — 3.01 previously printed PASS after scanning zero pages |
Claude Code (Opus 5.5) |
| 2026-08-08 | 0.2.1 | ai-drafted | Add first Code Packs (api, Notion REST API): 2.1 workspace-membership audit flagging members outside allowed email domains (GET /v1/users, requires user information capability), 3.1 published-page audit via the page object’s public_url field (POST /v1/search) — both verified against developers.notion.com; wire Code Implementation includes into 2.1 and 3.1. SCIM pack skipped: base URL/endpoints/pagination are documented in the SCIM help article but the auth header mechanics are not, failing the verification bar; audit-log pull skipped: no documented REST endpoint (webhook streaming only) | Claude Code (Fable 5) |
| 2026-08-08 | 0.2.0 | ai-drafted | Currency pass: corrected the audit log path to Settings → Admin → Audit log with 365-day retention and no pre-upgrade backfill (was “Organization Settings → Analytics”), corrected 3.2 to the real setting name “Disable moving or duplicating pages to other workspaces”, and replaced the stale “guests cannot use SAML SSO” note with the Enterprise “Require SAML SSO authorization for workspace access” option; added 3.4 DLP provider connections, 3.5 Notion AI admin settings, 3.6 agent/MCP connection governance, 3.7 API connection governance; added Workers audit events and SIEM webhook streaming to 4.1, guest disablement to 3.1, and SCIM token-hygiene sequencing to 1.3; rebuilt Appendix A and removed Trust Center / marketing sources from Appendix B (HIPAA claim rehomed to Notion’s HIPAA configuration guidance). Notion’s Privacy & Security category lists further articles (prompt-injection protections, custom-agent security, data residency, dormant accounts) not yet cited — their slugs must be discovered before citing, as a guessed slug 404’d. Tier 2: no CIS Benchmark, DISA STIG, or CISA SCuBA baseline exists for Notion (confirmed zero). Tier 3/4: not surveyed in this pass. | Claude Code (Opus 5) |
| 2026-06-29 | 0.1.1 | ai-drafted | Add cheat-sheet Description and Rationale for all controls | Claude Code (Opus 4.8) |
| 2025-02-05 | 0.1.0 | ai-drafted | Initial guide with SSO, organization security, and data protection | Claude Code (Opus 4.5) |
Contributing
Found an issue or want to improve this guide?
- Report outdated information: Open an issue with tag
content-outdated - Propose new controls: Open an issue with tag
new-control - Submit improvements: See Contributing Guide