T09 · Insecure Skill Coding Practices
- Location
templates/examples/content-scout-example.js:53- Finding
Shell Command Injection in Agent Integration Examples
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a real Notion integration, but its agent examples and helper scripts include unsafe command and credential-handling patterns that deserve review before installation.
Install only if you are comfortable giving the skill read/write access to the Notion pages and databases you share. Use a dedicated Notion integration with the smallest possible page/database scope, avoid running the documented exec examples with untrusted titles or JSON values, prefer argument-array execution or direct API calls, review setup-wizard.sh before use, and protect ~/.openclaw/.env with restrictive permissions.
templates/examples/content-scout-example.js:53Shell Command Injection in Agent Integration Examples
setup-wizard.sh:14Unsafe Import of Arbitrary Variables from the OpenClaw Credential File
notion-cli.js:136Predictable Shared Temporary File Allows Symlink Overwrite and Identifier Disclosure
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Add to ~/.openclaw/.env
NOTION_TOKEN=secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Add to ~/.openclaw/.env
NOTION_TOKEN=secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
### 3. Configure
```bash
# Add to ~/.openclaw/.env
NOTION_TOKEN=secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
The command echo "NOTION_TOKEN=..." >> ~/.openclaw/.env encourages writing a live credential directly into a plaintext file via shell history-visible commands. While not exfiltration, it increases exposure risk through shell history, local file disclosure, and accidental mishandling of secrets in shared environments.
npm install
# 2. Configure token
echo "NOTION_TOKEN=secret_xxxxxxxxxx" >> ~/.openclaw/.env
# 3. Test connection
node notion-cli.js test
The script loads and exports every key/value from ~/.openclaw/.env using command substitution and xargs. This is dangerous because a malformed or attacker-influenced .env file can inject unintended shell parsing behavior, and it also unnecessarily exposes all secrets from that file to child processes instead of only the Notion token.
# Check for NOTION_TOKEN
if [ -z "$NOTION_TOKEN" ]; then
if [ -f "$HOME/.openclaw/.env" ]; then
export $(cat "$HOME/.openclaw/.env" | grep -v '#' | xargs)
fi
fi
This line performs the actual bulk export of the .env file into the environment. If the file contains additional credentials or crafted content, those values become available to any subprocess launched later, increasing exposure of secrets and creating risk from unsafe shell parsing of untrusted configuration content.
# Check for NOTION_TOKEN
if [ -z "$NOTION_TOKEN" ]; then
if [ -f "$HOME/.openclaw/.env" ]; then
export $(cat "$HOME/.openclaw/.env" | grep -v '#' | xargs)
fi
fi
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import * as path from "path";
// Load env from common locations
dotenv.config({ path: path.join(process.env.HOME || "", ".openclaw", ".env") });
dotenv.config({ path: path.join(process.env.HOME || "", ".env") });
dotenv.config();
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import * as path from "path";
// Load env from common locations
dotenv.config({ path: path.join(process.env.HOME || "", ".openclaw", ".env") });
dotenv.config({ path: path.join(process.env.HOME || "", ".env") });
dotenv.config();
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import * as path from "path";
// Load env from common locations
dotenv.config({ path: path.join(process.env.HOME || "", ".openclaw", ".env") });
dotenv.config({ path: path.join(process.env.HOME || "", ".env") });
dotenv.config();
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Then load in scripts:
require('dotenv').config({
path: require('path').join(require('os').homedir(), '.openclaw', '.env')
});
The README promotes workspace search, reading, writing, and content management across any pages explicitly shared with the integration, but it does not clearly warn users that granting access enables both data exposure and data modification by the agent. In an agentic context, users may underestimate how much content can be searched or altered once a database or parent page is shared, increasing the risk of unintended disclosure or destructive writes.
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.
notion.so/my-integrations → New integration → Copy token
The skill documents access to environment-based credentials (NOTION_TOKEN) and execution of a local CLI, but it does not declare any explicit tool scope such as allowed tools or permissions. In agent environments, missing scope declarations can permit broader-than-expected command or environment access, increasing the chance of unintended secret exposure or misuse.
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.
---
name: notion
version: 0.1.0
description: Integrate with Notion workspaces to read pages, query databases, create entries, and manage content. Perfect for knowledge bases, project tracking, content calendars, CRMs, and collaborative documentation. Works with any Notion page or database you explicitly share with the integration.
---
# Notion Integration
This section instructs the agent to create, update, and append content in a live Notion workspace, but it does not clearly warn that these operations modify remote user data. In an agentic context, that omission can lead to accidental writes, overwrites, or content corruption if actions are taken without explicit user confirmation.
The test command enumerates accessible Notion pages/databases and prints titles and partial IDs directly to stdout with no warning, confirmation, or output-minimization. In agent or shared-terminal contexts, this can expose sensitive workspace metadata, project names, and identifiers to logs, transcripts, or unintended viewers even though the API call itself is legitimate.
When --numbered is used, the script writes a page-ID mapping file into the system temp directory without notifying the user or applying access controls. Temp directories are often readable by other local processes/users depending on platform and configuration, so this creates unintended local persistence of sensitive identifiers that may later be harvested from disk.
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.
echo ""
echo "Setup steps:"
echo "1. Go to https://www.notion.so/my-integrations"
echo "2. Create new integration"
echo "3. Copy the token (starts with 'secret_')"
echo "4. Add to ~/.openclaw/.env:"
echo " NOTION_TOKEN=secret_your_token_here"
The test command prints titles, IDs, and URLs for accessible Notion pages and databases directly to stdout, which can expose sensitive workspace metadata to terminal logs, calling processes, CI output, or other users on shared systems. While intended as a connectivity check, this disclosure can aid reconnaissance by revealing internal structure and identifiers that make follow-on access or social engineering easier.
The database query method retrieves potentially sensitive workspace records from Notion, and similar remote data access appears in this skill without any user-facing notice. Because the code performs network-backed access to user or organizational data with no prompt, logging, or documented warning in this file, users may be unaware of the scope of data being fetched.
This method retrieves a page and its child blocks from Notion, which may include sensitive user or organizational content. The file contains no confirmation, print/log notice, or inline user warning indicating that remote content will be accessed and returned.
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.
return { page, blocks: blocks.results };
}
// Add entry to database
async addEntry(databaseId: string, properties: any) {
const cleanId = this.cleanId(databaseId);
return await this.client.pages.create({
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.
return { page, blocks: blocks.results };
}
// Add entry to database
async addEntry(databaseId: string, properties: any) {
const cleanId = this.cleanId(databaseId);
return await this.client.pages.create({
The search method sends the provided query to Notion via an external network call, which can disclose user-entered text to a third-party service. In this file, there is no confirmation prompt, warning, or user-facing logging indicating that the query will be transmitted off-system.
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.
Update select/multi_select options to match your workflow:
- Add/remove platforms to match your social presence
- Adjust project statuses for your process
- Create custom tags for your niche
### Creating Views
No suspicious patterns detected.