Back to skill

Security audit

Notion 2025 API Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed Notion integration, but it stores a long-lived key locally and includes helper-script safety gaps that could expose the key or alter more Notion data than intended.

Install only if you are comfortable granting this skill access to the Notion pages/databases you explicitly share with its integration. Use a least-privilege Notion integration, avoid running write or batch examples on important data without review, do not pass untrusted property names or JSON into the helper, and rotate the Notion token if it may have been exposed.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/notion_helper.sh:92
Finding

Notion API Token Exposed Through Process Arguments

Content
View full analysis
/cmdline`. The practical accessibility of another process's arguments depends on operating-system configuration, user boundaries, container isolation, and process-inspection restrictions. This issue affects every helper operation because query, create, update, and get requests all pass the token through `curl` arguments. ### Attack Path 1. The victim invokes any helper command, such as `query`, `create`, `update`, or `get`. 2. The script reads the Notion token from the local secrets file into `NOTION_KEY`. 3. The shell expands the token into the `curl` authorization-header argument. 4. During the lifetime of the request, a local attacker or compromised process with adequate process-inspection permissions observes the `curl` argument vector. 5. The attacker extracts the bearer token from the authorization header. 6. The attacker uses the captured token to make independent Notion API requests. This path requires local process v ...[truncated 742 chars]
Remediation
View remediation
"$curl_config" curl --silent --config "$curl_config" \ -X GET "$BASE_URL/pages/$page_id" \ -H "Notion-Version: $API_VERSION" ``` The implementation should also verify that the selected temporary directory is private and that cleanup occurs for all script exit paths. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/notion_helper.sh:139
Finding

Unescaped Property Name Allows JSON Structure Injection

Content
View full analysis
" exit 1 fi if ! validate_notion_id "$page_id" "page_id"; then exit 1 fi # Security: Validate value is valid JSON if ! echo "$value" | jq empty 2>/dev/null; then log_error "Invalid JSON in value: $value" exit 1 fi local response=$(curl -s -X PATCH "$BASE_URL/pages/$page_id" \ -H "Authorization: Bearer $NOTION_KEY" \ -H "Notion-Version: $API_VERSION" \ -H "Content-Type: application/json" \ -d '{"properties": {'$property': '$value'}}') ``` ### Technical Analysis The script verifies that `value` is syntactically valid JSON, but it does not validate or JSON-encode `property`. Instead, `property` is inserted directly into the request body: ```bash -d '{"properties": {'$property': '$value'}}' ``` A property argument can therefore contain JSON delimiters, values, and additional property names. This permits an attacker to alter the structure of the generated `properties` object rather than selecting only one intended property. For example, a crafted property argument with the conceptual structure below can terminate the first property value and introduce another property key: ```text "Status": {"status": {"name": "Complete"}}, "SensitiveProperty" ``` When combined with a valid JSON `value`, the resulting request can update both `Status` and `SensitiveProperty`. The exact property names and values must be valid for the target Notion database schema. Because the interpolation is also unquoted at the shell level, word splitting and pathname expansion can further ...[truncated 2025 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (50)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · SECURITY.md (reported line 305)May include surrounding context.

If using untrusted input, use file-based approach:

echo "$user_input" | jq -Rs '.' > /tmp/input.json ./notion_helper.sh ... < /tmp/input.json rm /tmp/input.json

text

---

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

A description-behavior mismatch is a real security concern because reviewers and users rely on the description to understand what the skill can do. If the implementation supports undeclared retrieval or omits a declared function, the skill may be used in ways that bypass informed consent or security expectations.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 11)May include surrounding context.

md
✅ **Database Operations**
- Query entries with filters and sorting
- Create new database entries
- Update entry properties
- Batch operations support

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README instructs users to place a live API key in a local secrets file and then immediately uses examples that perform authenticated API calls and write operations, but it does not explicitly warn that these commands transmit credentials to an external service and can modify remote Notion content. In a skill context, users may copy-paste commands verbatim, increasing the risk of unintended secret handling and destructive changes.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 68)May include surrounding context.

bash
mkdir -p ~/.openclaw/workspace/secrets
echo "ntn_YOUR_KEY_HERE" > ~/.openclaw/workspace/secrets/notion_api_key.txt
chmod 600 ~/.openclaw/workspace/secrets/notion_api_key.txt

3. Share Notion Pages/Databases

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SECURITY.md (reported line 297)May include surrounding context.

bash
mkdir -p ~/.openclaw/workspace/secrets
echo "ntn_YOUR_KEY_HERE" > ~/.openclaw/workspace/secrets/notion_api_key.txt
chmod 600 ~/.openclaw/workspace/secrets/notion_api_key.txt

3. Share Notion Pages/Databases

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · README.md (reported line 87)May include surrounding context.

md
# Set your data_source_id and filter
DATA_SOURCE_ID="your_data_source_id"

curl -s -X POST "https://api.notion.com/v1/data_sources/$DATA_SOURCE_ID/query" \
  -H "Authorization: Bearer $(cat ~/.openclaw/workspace/secrets/notion_api_key.txt)" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 97)May include surrounding context.

}' | jq '.results[]'

text

### Create a Database Entry

```bash
DATABASE_ID="your_database_id"

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · README.md (reported line 102)May include surrounding context.

bash
DATABASE_ID="your_database_id"

curl -s -X POST "https://api.notion.com/v1/pages" \
  -H "Authorization: Bearer $(cat ~/.openclaw/workspace/secrets/notion_api_key.txt)" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SECURITY.md (reported line 176)May include surrounding context.

md
**Risk:** Key stored in plaintext file  
**Mitigation:**
- ✅ Key stored in user's home directory (not in repo)
- ✅ File permissions can be: `chmod 600`
- ✅ Documented in README
- ✅ Notion supports key rotation

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Earlier in the document, the skill states that JSON injection was fixed and that all user input is now properly escaped and validated (for example at L044-L084 and L167-L169). The later 'UNSAFE Usage Patterns' section says passing user input directly to create/query is unsafe, which contradicts the document's own claim that the script handles such input safely after the fix.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SECURITY.md (reported line 282)May include surrounding context.

If key is ever exposed:

1. Go to https://notion.so/my-integrations

2. Delete the compromised key

3. Create new key

4. Update ~/.openclaw/workspace/secrets/notion_api_key.txt

text

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes shell-based network operations and reads a secret from disk, but it does not declare an explicit tool scope such as allowed tools or permissions. That omission weakens policy enforcement and reviewability, making it easier for a skill to exercise shell capabilities more broadly than users or orchestrators may expect.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 67)May include surrounding context.

bash
ENTRY_ID="YOUR_ENTRY_ID"

curl -s -X PATCH "https://api.notion.com/v1/pages/$ENTRY_ID" \
  -H "Authorization: Bearer $NOTION_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/EXAMPLES.md (reported line 68)May include surrounding context.

bash
ENTRY_ID="YOUR_ENTRY_ID"

curl -s -X PATCH "https://api.notion.com/v1/pages/$ENTRY_ID" \
  -H "Authorization: Bearer $NOTION_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 84)May include surrounding context.

bash
PAGE_ID="YOUR_PAGE_ID"

curl -s -X PATCH "https://api.notion.com/v1/blocks/$PAGE_ID/children" \
  -H "Authorization: Bearer $NOTION_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/EXAMPLES.md (reported line 89)May include surrounding context.

bash
PAGE_ID="YOUR_PAGE_ID"

curl -s -X PATCH "https://api.notion.com/v1/blocks/$PAGE_ID/children" \
  -H "Authorization: Bearer $NOTION_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The skill instructs users to store a long-lived API key in a persistent file under the workspace. Persistent credentials increase the blast radius of compromise because any other process, skill, or accidental disclosure affecting that workspace can potentially reuse the token to access Notion data.

Content

Scanner excerpt · SKILL.md (reported line 145)May include surrounding context.

md
## Setup

1. Create integration at https://notion.so/my-integrations
2. Copy API key
3. Store in `~/.openclaw/workspace/secrets/notion_api_key.txt`
4. Share target Notion pages/databases with your integration (Invite → select integration)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The document repeatedly demonstrates loading a bearer token from a local secrets file and transmitting it to a remote service without any guidance on safe credential handling, scope minimization, or log hygiene. While sending the token to Notion is expected for the integration, the lack of warnings can normalize unsafe reuse, disclosure in terminal history, or execution in untrusted contexts.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 35)May include surrounding context.

md
NOTION_KEY=$(cat ~/.openclaw/workspace/secrets/notion_api_key.txt)
DATA_SOURCE_ID="YOUR_DATA_SOURCE_ID"  # Replace with your actual data source ID

curl -s -X POST "https://api.notion.com/v1/data_sources/$DATA_SOURCE_ID/query" \
  -H "Authorization: Bearer $NOTION_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/EXAMPLES.md (reported line 13)May include surrounding context.

md
NOTION_KEY=$(cat ~/.openclaw/workspace/secrets/notion_api_key.txt)
DATA_SOURCE_ID="YOUR_DATA_SOURCE_ID"  # Replace with your actual data source ID

curl -s -X POST "https://api.notion.com/v1/data_sources/$DATA_SOURCE_ID/query" \
  -H "Authorization: Bearer $NOTION_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/EXAMPLES.md (reported line 138)May include surrounding context.

md
NOTION_KEY=$(cat ~/.openclaw/workspace/secrets/notion_api_key.txt)
DATA_SOURCE_ID="YOUR_DATA_SOURCE_ID"  # Replace with your actual data source ID

curl -s -X POST "https://api.notion.com/v1/data_sources/$DATA_SOURCE_ID/query" \
  -H "Authorization: Bearer $NOTION_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/EXAMPLES.md (reported line 33)May include surrounding context.

md
---

## Example 2: Create a Blog Series Entry

**Task:** Add a new series to the Blog Series database

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The examples include multiple write operations to the live Notion API (creating pages, updating properties, appending blocks, and batch updates) but provide no explicit warning that running them will modify external user data. In an agent skill context, examples are often copied or adapted directly, so omission of mutation warnings increases the risk of unintended data changes in a real workspace.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 48)May include surrounding context.

md
NOTION_KEY=$(cat ~/.openclaw/workspace/secrets/notion_api_key.txt)
DATABASE_ID="YOUR_DATABASE_ID"  # Blog Series database

curl -s -X POST "https://api.notion.com/v1/pages" \
  -H "Authorization: Bearer $NOTION_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \

Static analysis

No suspicious patterns detected.