v0.2.2 AI Drafted AI Validated

Notion Hardening Guide

Productivity Last updated: 2026-10-04

Collaboration platform hardening for Notion including SAML SSO, workspace security, DLP, AI and MCP connection governance, and audit logging

View:

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

  1. Authentication & SSO
  2. Organization Security
  3. Data Protection
  4. Monitoring & Compliance
  5. 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

  1. 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
  2. Navigate to: Settings → Identity → Domain management → Verified domains → Add domain, then verify your organization’s domain
  3. Domain verification is required before SSO setup — Enable SAML SSO stays disabled until a domain is verified

Step 2: Access SSO Configuration

  1. For Business: Navigate to Settings → Identity → SAML single sign-on (SSO) and use Enable SAML SSO / Edit SAML SSO configuration
  2. For Enterprise: Open the workspace switcher → Manage organization → General tab → SAML configurations

Step 3: Configure SAML Settings

  1. Copy the Assertion Consumer Service (ACS) URL
  2. Enter in your IdP portal
  3. Configure IdP with:
    • ACS URL from Notion
    • Entity ID
  4. 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

  1. Provide either IdP URL or IdP metadata XML
  2. Complete configuration
  3. 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

  1. Navigate to: Settings → Identity → SAML single sign-on (SSO) → Login method
  2. Default login method is Any method
  3. Change to Only SAML SSO

Step 2: Require SAML Authorization for Workspace Access (Enterprise)

  1. Enable Require SAML SSO authorization for workspace access
  2. 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”
  3. 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

  1. 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
  2. Protect those owner accounts accordingly — they are the standing bypass (see 2.3)
  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

  1. Navigate to: Settings → Identity → SCIM provisioning (workspace), or the workspace switcher → Manage organization (Enterprise organization owners)
  2. Open SCIM tokens — below Enterprise the console reads “Upgrade to generate a token to configure SCIM”
  3. Generate SCIM API token

Step 2: Configure IdP SCIM

  1. Add Notion SCIM integration in IdP
  2. Enter SCIM endpoint URL
  3. Enter API token

Step 3: Configure Provisioning Settings

  1. Turn on Suppress invite emails from SCIM provisioning
  2. Control internal rollout communication
  3. Test user synchronization
  4. Supported IdPs include Okta, OneLogin, Rippling, and custom SCIM applications

Step 4: Manage Token Hygiene

  1. Generate a separate SCIM API token for each workspace you manage via SCIM — tokens are workspace-scoped, not organization-wide
  2. 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
  3. 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

  1. Navigate to: Settings → General
  2. Configure Allowed email domains
  3. Restrict to corporate domains only

Step 2: Disable Automatic Account Creation

  1. 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)
  2. Prevents users from creating accounts through SSO
  3. Requires explicit provisioning

Step 3: Configure Membership

  1. Navigate to: Settings → People and review Members and Guests
  2. Remove unauthorized users
  3. 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
hth-notion-2.01-audit-workspace-members.sh View source on GitHub ↗
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

  1. Navigate to: Settings → Teamspaces; turn on Limit teamspace creation to workspace owners and review Default teamspaces
  2. Organize teamspaces by team or function
  3. Limit membership appropriately

Step 2: Configure Team Space Security

  1. Open each teamspace’s ··· → Teamspace settings → Security
  2. Set Who can invite or remove teamspace members and Who can edit teamspace sidebar
  3. 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

  1. Navigate to: Settings → People
  2. Review workspace owners
  3. Document all administrators

Step 2: Apply Least Privilege

  1. Limit workspace owners to 2-3 users
  2. Use member roles for regular users
  3. 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
hth-notion-2.03-audit-workspace-owners.sh View source on GitHub ↗
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

  1. Navigate to: Settings → Security → Members & guests → Who can invite guests to pages
  2. Restrict guest invitations — below Enterprise the console reads “Upgrade to disable the ability for members to invite guests to pages”
  3. Limit guest capabilities

Step 1b: Turn Guests Off Entirely (Enterprise)

  1. Enterprise workspace owners can enable Disable guests, which blocks external invitations outright — the cleanest control where external collaboration is not a business requirement
  2. 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
  3. Source: Notion Enterprise security provisions

Step 2: Configure Public Pages

  1. Audit at Settings → Public pages (Notion Sites, Public forms, Anyone with the link, Shared AI chats, Domains)
  2. Unpublish anything not deliberately public
  3. On Enterprise, turn on Settings → Security → Disable public forms, page links, and Notion Sites

Step 3: Configure Link Sharing

  1. Set default sharing permissions
  2. Restrict “Anyone with link” access
  3. Require explicit permissions

Code Implementation

Code Pack: API Script
hth-notion-3.01-audit-public-pages.sh View source on GitHub ↗
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

  1. Navigate to: Settings → Security (Enterprise — below Enterprise the toggle reads “Upgrade”)
  2. Turn on Disable duplicating pages to other workspaces
  3. This blocks both the copy path and the move path out of the workspace

Step 2: Review Exceptions

  1. Document any business need for moving or duplicating content externally
  2. Consider enabling per team space if needed
  3. 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

  1. Navigate to: Settings → Security
  2. Turn on Disable exports
  3. Per teamspace: ··· → Teamspace settings → Security → Disable export, keeping export available only in teamspaces that need it

Step 2: Audit Export Activity

  1. Review export events in the audit log (4.1)
  2. Monitor for unusual patterns
  3. 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

  1. Confirm which supported provider your organization uses — Nightfall AI is the currently available integration
  2. As an organization owner, connect the provider from Settings → Connections → Discover → DLP → Nightfall AI
  3. Authorize the connection with the scope the provider requires

Step 2: Define Detection and Remediation Policy

  1. Configure the detectors that match your obligations (PII, PHI, payment data, API keys and other credentials)
  2. Decide the remediation action per detector — alert, redact, or restrict — rather than accepting the provider default everywhere
  3. 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

  1. Navigate to: Settings → Notion AI
  2. 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

  1. Review Settings → Notion AI → AI connectors and remove connectors to third-party apps without a business justification
  2. Set Enable web search for workspace deliberately
  3. 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

  1. 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
  2. Set Enable image generation (available on Business and Enterprise)
  3. Review agent personalization settings (name, appearance, custom instructions) as part of the same review

Step 4: Bound AI Meeting Notes Retention

  1. Navigate to: Settings → Meeting notes
  2. Set Automatic transcript deletion (Enterprise — the default is Never), Store audio locally, and Enforce consent for all workspace members
  3. 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)

  1. Navigate to: Settings → Notion MCP → Manage workspace clients
  2. 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
  3. Use Disconnect all users (under Disconnect all connections to Notion MCP) to revoke MCP connections workspace-wide during an incident
  4. 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

  1. 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
  2. Where an agent only needs to read, enable only read-only tools for it

Step 3: Scope Each Agent Narrowly

  1. Create agents for specific purposes rather than one agent with access to everything, and avoid granting unnecessary page or database access
  2. Review each agent’s enabled tools and resources after adding a connection, and disable what it does not need
  3. 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

  1. Navigate to: Settings → Connections → Manage
  2. 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”)
  3. 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

  1. For each connection, view all members who have it installed
  2. Disconnect members from connections that are unused, unapproved, or belong to a vendor with an open security issue

Step 3: Scope Page Access

  1. For each connection, select the specific pages it may access
  2. 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

  1. Workspace: Settings → Audit log (Admin group of the sidebar). Organization: workspace switcher → Manage organization → Data & Compliance → Audit log
  2. Filter by date, person or agent, event type, or related activity
  3. Export as CSV (filters apply to the export) on a schedule if you are not streaming

Step 2: Monitor Key Events

  1. Page events and teamspace events
  2. Workspace events — including SSO and security configuration changes
  3. Account events — provisioning, deprovisioning, and role changes
  4. Workers events — agent/worker creation, deployment, runs, and secrets
  5. Form events and data source events
  6. Content exports and sharing changes

Step 3: Stream to a SIEM

  1. Configure event streaming to your SIEM from Settings → Connections → Discover → SIEM — Notion publishes partner guidance for Splunk, Sumo Logic, Panther, and Datadog
  2. 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
  3. Note that syslog is not supported — webhook delivery is the only streaming transport
  4. 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

  1. 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
  2. Review workspace usage
  3. Monitor member activity

Step 2: Review Security Metrics

  1. Track guest access patterns
  2. Monitor sharing activity
  3. 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:

API Documentation:

Compliance Frameworks:

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?