Back to skill

Security audit

Notion IM Helper

Security checks for vulnerabilities and agentic risk

Overview

The skill is a plausible Notion sync helper, but its actual behavior is broader and more destructive than its append-only single-page description suggests.

Review before installing. Use a Notion integration authorized only to a dedicated page, avoid broad workspace access, and be aware that messages may be written to Notion automatically, search/monthly features read existing Notion content, local images are uploaded, and undo can delete Notion blocks rather than only append new records.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/search_notes.py:25
Finding

Workspace-Wide Notion Search Exceeds the Declared Single-Page Scope

Content
View full analysis

Vulnerability Details

File Location: scripts/search_notes.py:25-46
Vulnerability Type: Excessive Notion data access and insufficient scope restriction
Risk Level: Medium

Vulnerable Code

python
def search(query, page_size=10):
    """Search using Notion Search API with retry on rate limit."""
    body = {
        "query": query,
        "page_size": page_size,
        "sort": {
            "direction": "descending",
            "timestamp": "last_edited_time",
        },
    }
    for attempt in range(3):
        data = json.dumps(body).encode()
        req = urllib.request.Request(
            f"{BASE_URL}/search",
            data=data,
            headers=get_headers(),
            method="POST",
        )
        try:
            resp = urllib.request.urlopen(req)
            return json.loads(resp.read())

Technical Analysis

The Skill is described as operating on a single Notion page identified by NOTION_PARENT_PAGE_ID. However, the search implementation calls Notion's general /v1/search endpoint and does not restrict or post-filter results to that configured page or its descendants.

The endpoint searches objects visible to the Notion integration. If the integration has access to multiple pages or data sources, the script may retrieve metadata for content unrelated to the configured target page. Returned results are subsequently formatted to expose page titles, edit dates, and portions of page URLs.

The request necessarily transmits the Notion integration token and user-supplied search term to Notion. Sending these values to the official Notion API is consistent with search functionality, but using the integration's entire visible workspace scope is broader than the declared single-page behavior.

Attack Path

  1. A user grants the Notion integration access to the intended page and one or more unrelated pages or data sources.
  2. An agent or user in ...[truncated 773 chars]
Remediation
View remediation

Remediation Suggestions

  • Replace workspace-wide search with traversal and local filtering of blocks beneath NOTION_PARENT_PAGE_ID.
  • If the Notion Search API must be used, validate every returned page against the configured page hierarchy before displaying it.
  • Explicitly document workspace-wide search and request informed user consent if that broader scope is intentional.
  • Recommend that users authorize the integration only for the target page and avoid granting workspace-wide access.
  • Add tests proving that search results outside the configured page are discarded.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/notion_client.py:143
Finding

Undo Can Delete a Notion Block Not Created by the Skill

Content
View full analysis

Vulnerability Details

File Location: scripts/notion_client.py:143-166
Vulnerability Type: Missing ownership validation for destructive operations
Risk Level: Medium

Vulnerable Code

python
    # No pending batch, delete single last block
    cursor = None
    last_block = None
    while True:
        params = f"page_size=100"
        if cursor:
            params += f"&start_cursor={cursor}"
        data = api_request("GET", f"blocks/{PAGE_ID}/children?{params}")
        if data.get("error") or "results" not in data or not data["results"]:
            break
        last_block = data["results"][-1]
        if data.get("has_more") and data.get("next_cursor"):
            cursor = data["next_cursor"]
        else:
            break

    if not last_block:
        print("OK| 没有可撤回的记录")
        return

    block_id = last_block["id"]
    result = api_request("DELETE", f"blocks/{block_id}")
    if result.get("error"):
        _emit_error(result)
        return
    print("OK| 已撤回最后一条记录")

Technical Analysis

Recent Skill-created block identifiers are stored in .pending_batch.json for five minutes. If that state is absent, invalid, or expired, delete_last_block() enumerates the configured page and deletes its last block without checking whether the Skill created it.

This creates a time-of-check and ownership problem. The last block may have been created manually by the user, by another Notion integration, or by a concurrent Skill invocation whose state was overwritten. The detailed documentation mentions deleting the last block after the five-minute window, but this behavior conflicts with the broader append-only and “never modify or delete existing blocks” safety claims and is not necessary for a safe undo implementation.

Attack Path

  1. A user or another integration creates a block on the configured Notion page.
  2. The Skill's pending batch file is mi ...[truncated 936 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove the fallback that deletes the page's current last block.
  • Permit undo only for block IDs recorded at creation time and verified as belonging to the Skill.
  • Persist an append-only operation journal with restrictive file permissions, operation IDs, timestamps, page IDs, and created block IDs.
  • Do not overwrite ownership history with only the most recent batch; retain enough verified history to implement the desired undo period safely.
  • If no verified Skill-created block is available, return a non-destructive error instead of guessing.
  • Add concurrency tests covering manual edits and writes by other integrations between record and undo operations.

T08 · Insecure Dependencies

Warning
Location
scripts/notion_client.py:246
Finding

Unpinned and Undeclared Image Upload Dependency Receives Sensitive Inputs

Content
View full analysis

Vulnerability Details

File Location: scripts/notion_client.py:246-263
Vulnerability Type: Uncontrolled third-party dependency and supply-chain exposure
Risk Level: Medium

Vulnerable Code

python
    try:
        from notion_upload import notion_upload as nu
    except ImportError:
        print("ERROR| notion-upload 库未安装,请运行: pip install notion-upload")
        return None

    if not API_KEY:
        print("ERROR|AUTH")
        return None

    file_name = os.path.basename(file_path)
    try:
        uploader = nu(file_path, file_name, API_KEY, enforce_max_size=True)
        file_id = uploader.upload()
        if file_id:
            # Small delay to avoid rate limit on rapid successive uploads
            import time
            time.sleep(0.5)
            return file_id

The declared setup instructions only identify a different dependency:

text
pip install notion-client

Technical Analysis

Local image upload dynamically imports notion_upload. If it is missing, the script instructs the user to run an unversioned pip install notion-upload. The project does not provide a pinned dependency manifest, hashes, a reviewed version, or an integrity-verification mechanism for this package.

The dependency is particularly sensitive because its constructor receives both the local file path and the Notion API token. Python packages can execute arbitrary code during installation and import. Therefore, a compromised release, account takeover, dependency-confusion condition, or malicious package substitution could expose the integration credential, read local files, or execute code with the user's privileges.

The audit did not establish that the current package is malicious. The vulnerability is the unpinned and insufficiently controlled supply-chain trust relationship.

Attack Path

  1. A user invokes local image upload without notion-upload installed.
  2. T ...[truncated 1044 chars]
Remediation
View remediation

Remediation Suggestions

  • Explicitly declare every runtime dependency in a lock file or equivalent dependency manifest.
  • Pin notion-upload to a reviewed version and verify package hashes during installation.
  • Review the package's publisher, source repository, release process, and transitive dependencies before trusting it with tokens and files.
  • Prefer implementing the documented Notion File Upload API directly, reducing the number of third parties that receive credentials and local data.
  • Never recommend an unversioned installation command from runtime error handling.
  • Use a dedicated virtual environment and a minimally privileged Notion integration.
  • Document that local files and the integration token are passed to a third-party library.
  • Update SKILL.md and config.yaml so installation requirements accurately match runtime behavior.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Summary and quote retrieval features read and analyze historical Notion content, which is materially different from simple append-only sync. This broadens the skill into content retrieval and analysis, increasing privacy and data-mining risk if users expect only write-only behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Summary and quote retrieval features read and analyze historical Notion content, which is materially different from simple append-only sync. This broadens the skill into content retrieval and analysis, increasing privacy and data-mining risk if users expect only write-only behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Summary and quote retrieval features read and analyze historical Notion content, which is materially different from simple append-only sync. This broadens the skill into content retrieval and analysis, increasing privacy and data-mining risk if users expect only write-only behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Summary and quote retrieval features read and analyze historical Notion content, which is materially different from simple append-only sync. This broadens the skill into content retrieval and analysis, increasing privacy and data-mining risk if users expect only write-only behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest says the skill is append-only to a single page, yet the documented undo command deletes existing blocks. Contradictory safety claims undermine informed consent and can cause users or orchestrators to permit a destructive skill they believe is non-destructive.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The file simultaneously instructs callers to never modify or delete existing Notion blocks and advertises an undo command that deletes blocks. This internal contradiction is dangerous because agents may rely on the safer instruction while still exposing a destructive operation to users.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
93% confidence
Finding

The description says the skill may trigger when a message merely contains recording intent, and the trigger configuration includes broad everyday terms like 'search' and 'notion'. This creates a high risk of accidental invocation, causing unintended syncing of chat content, privacy leakage into Notion, or execution of side effects without clear user intent.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

Many keywords in the trigger list overlap with normal conversation, including generic words such as todo, idea, search, link, monthly, undo, and notion. In an IM context, broad keyword matching can easily capture unrelated messages and send sensitive or irrelevant content to Notion without the user realizing the skill was activated.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill manifest says writes are append-only to a single Notion page, but this code can delete previously written content via delete_last_block(), including batch deletion of multiple blocks. That mismatch expands the skill's effective authority beyond what a user would reasonably expect, enabling destructive modification of existing page content if the delete path is exposed or triggered.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill is advertised as append-only, but the undo command calls delete_last_block(), which can remove existing content from the target Notion page. This breaks the stated trust boundary and enables destructive modification of data, especially if invoked accidentally or by an upstream agent assuming only additive behavior.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The single-letter prefixes are broad enough that ordinary conversational input beginning with a short token and space can unintentionally trigger data-writing actions. In this skill, matched content is automatically routed to scripts that append content to Notion, so misclassification can cause unintended persistence of user messages and accidental disclosure of sensitive content into the configured page.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill exposes an undo/撤回 command that deletes the last block batch within a time window, but the user-facing description emphasizes append-only behavior and does not clearly warn about this destructive capability. A user may invoke it casually or accidentally, leading to unexpected deletion of recently synced content and undermining the stated expectation that data is only appended.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The fallback logic treats unmatched text as actionable content and defaults to idea, which means nearly any message can trigger a write to Notion without explicit user intent. Because this is an append-only integration connected to an external API, ambiguous detection increases the chance of exfiltrating incidental, private, or unrelated chat content into persistent storage.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill documents capabilities that read environment variables, write/read local files, and make network requests, but it declares no explicit tool scope or permission boundaries. In an agent setting, this weakens least-privilege controls and makes it easier for the skill to access sensitive data or perform unintended external actions without clear operator review.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Single-letter triggers like d, n, t, i, l, p, and z are highly collision-prone in normal conversation. In a chat-driven agent, this can cause accidental activation, misclassification of user intent, and unintended transmission of user content or files to Notion.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The smart-detection rules auto-infer actions from broad patterns like URLs, dates, checkboxes, or defaulting to idea without any explicit command. This makes activation boundaries unclear and increases the chance that ordinary chat content will be silently synced or uploaded to Notion.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation explains that local file paths and remote URLs can be uploaded or referenced in Notion, but it does not provide a strong, upfront user warning that message-supplied files and links may leave the local environment. This can lead to unintentional exfiltration of sensitive local images or internal URLs.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The description is very broad and describes multiple content types and operations without stating clear trigger conditions, scope boundaries, or user confirmation requirements. In an agent skill, vague activation scope can cause the skill to run in unintended contexts and sync sensitive IM content to Notion when the user did not clearly intend that action.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The only natural-language description is written in Chinese, which may signal a language-specific skill experience without offering a user language choice or documenting a justified locale restriction. This can violate language or locale policy when no opt-in or region-specific constraint is stated.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest promises append-only behavior to a single Notion page, but the trigger surface explicitly includes undo, search, and monthly-report style operations that imply retrieval, mutation, or broader workflow behavior. This mismatch is dangerous because users and higher-level agents may grant trust or auto-enable the skill under a false assumption of limited write-only scope.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The inline text states '只追加不删除,安全可靠' ('append only, no deletion, safe and reliable') while the trigger list advertises undo capability, which directly contradicts the safety claim. Contradictory safety assertions are risky because they can mislead users, reviewers, or automation into approving a skill with broader or reversible effects than disclosed.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The user-facing description is entirely in Chinese, and the configured triggers are primarily Chinese-language forms, with no indication that users may choose another language or that the skill is intentionally region-specific. This can violate language/locale policy when a skill implicitly enforces one language without opt-in.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Several prefix patterns are common in ordinary chat, such as '今天:', '今日', or short forms like '搜:' and 'done:'. Prefixes this broad are unsafe in messaging environments because they can be used naturally in conversation, increasing accidental activation and unintended data transfer to the connected Notion workspace.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The guide text is entirely in Chinese and instructs the user to continue with a Chinese trigger phrase ("d 测试一下"). This creates a locale/language constraint in the skill's natural-language interface without documenting user choice or a justified region-specific limitation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This code emits user-facing status text in Chinese, and the pattern continues throughout the file. The skill does not offer a language/locale choice or document a justified locale restriction, which is a natural-language policy violation under the language/locale rule.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.