Back to skill

Security audit

OpenNotebook

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real OpenNotebook client, but it exposes broad administrative and destructive actions with weak disclosure and credential-safety gaps.

Review this carefully before installing. Only use it with an OpenNotebook API key whose permissions you are comfortable giving to an agent, avoid passing keys with --api-key, protect ~/.openclaw/opennotebook.env, and require explicit confirmation before uploads, deletes, credential changes, settings changes, model changes, or migrations.

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
opennotebook.py:319
Finding

API Key Exposure Through Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Locations:

  • opennotebook.py:319
  • opennotebook.py:526-527
  • test_integration.py:418-432

Vulnerability Type: Sensitive credential exposure through process arguments
Risk Level: Medium

Vulnerable Code

python
parser.add_argument("--api-key", help="API 密钥")
python
if args.api_key:
    config.api_key = args.api_key
python
base_url = self.client.notebooks.config.base_url
api_key = self.client.notebooks.config.api_key

commands = [
    (["--base-url", base_url, "--api-key", api_key, "health"], "健康检查"),
    (["--base-url", base_url, "--api-key", api_key, "notebooks", "list"], "列出笔记本"),
    (["--base-url", base_url, "--api-key", api_key, "sources", "list"], "列出源"),
    (["--base-url", base_url, "--api-key", api_key, "notes", "list"], "列出笔记"),
    (["--base-url", base_url, "--api-key", api_key, "models", "list"], "列出模型"),
    (["--base-url", base_url, "--api-key", api_key, "transformations", "list"], "列出转换"),
    (["--base-url", base_url, "--api-key", api_key, "search", "query", "测试", "--limit", "3"], "搜索"),
]

for cmd, desc in commands:
    result = subprocess.run(
        ["python3", str(cli_path)] + cmd,
        capture_output=True,
        text=True
    )

Technical Analysis

The CLI accepts the bearer API key directly through the --api-key argument. Command-line arguments may be exposed through shell history, process inspection facilities, CI/CD execution logs, endpoint-monitoring products, crash diagnostics, or debugging output.

The integration test compounds this issue by placing the same key in the argument vector of every spawned CLI process. Although subprocess.run uses an argument list rather than a shell and is therefore not vulnerable to shell injection here, the secret remains visible as process metadata while each child process executes.

Attack Path

  1. A user invokes the CLI or integration te ...[truncated 1028 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove or deprecate the --api-key option for normal use.

  2. Read the key from OPENNOTEBOOK_API_KEY, a protected credential file, standard input, or an operating-system secret store.

  3. If interactive entry is required, use getpass.getpass() so the key is not echoed or retained in shell history.

  4. Change integration tests to pass the key through a restricted child-process environment instead of the argument vector:

    python
    child_env = os.environ.copy()
    child_env["OPENNOTEBOOK_API_KEY"] = api_key
    
    result = subprocess.run(
        ["python3", str(cli_path), "--base-url", base_url, "health"],
        env=child_env,
        capture_output=True,
        text=True
    )
    
  5. Ensure CI systems mask OPENNOTEBOOK_API_KEY and do not print child environments.

  6. Rotate any API key that has already been supplied through command-line arguments in shared, monitored, or logged environments.

T09 · Insecure Skill Coding Practices

Warning
Location
opennotebook.py:66
Finding

API Key Configuration File Is Written Without Enforced Restrictive Permissions

Content
View full analysis

Vulnerability Details

File Location: opennotebook.py:66-75
Vulnerability Type: Insecure plaintext credential storage permissions
Risk Level: Medium

Vulnerable Code

python
def save(self):
    """保存配置文件"""
    CONFIG_FILE.parent.mkdir(parents=True, exist_ok=True)
    with open(CONFIG_FILE, "w") as f:
        f.write("# OpenNotebook 配置\n")
        f.write(f"OPENNOTEBOOK_BASE_URL={self.base_url}\n")
        if self.api_key:
            f.write(f"OPENNOTEBOOK_API_KEY={self.api_key}\n")
        f.write(f"OPENNOTEBOOK_TIMEOUT={self.timeout}\n")

Technical Analysis

Config.save() stores the bearer API key as plaintext in ~/.openclaw/opennotebook.env but does not enforce a secure mode on either the parent directory or the credential file.

The permissions of a newly created file depend on the process umask. Under a permissive or incorrectly configured umask, the file may be readable by other local users. If the file already exists, opening it with mode "w" truncates the content but preserves its existing permissions, so a previously insecure mode remains insecure.

The parent directory is similarly created without an explicit restrictive mode. This can allow unintended directory traversal or file access, depending on the effective umask and existing filesystem permissions.

Attack Path

  1. A user configures an OpenNotebook API key and invokes Config.save().
  2. The configuration directory or file is created under a permissive umask, or an existing file already has broad permissions.
  3. The API key is written in plaintext without correcting those permissions.
  4. Another local user or compromised process reads ~/.openclaw/opennotebook.env.
  5. The attacker extracts OPENNOTEBOOK_API_KEY.
  6. The attacker authenticates to the configured OpenNotebook API and performs operations allowed by the key.

Impact Assessment

Exploitation requires local filesystem read access und ...[truncated 451 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create the configuration directory with mode 0700.
  2. Create the credential file atomically with mode 0600, avoiding a permission window during creation.
  3. Correct the permissions of existing directories and files before writing.
  4. Prefer an operating-system credential store instead of a plaintext environment file where available.
  5. Refuse to load a credential file that is owned by another user or has group/world-readable permissions, unless the user explicitly overrides the warning.

Example hardening approach:

python
def save(self):
    CONFIG_FILE.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
    os.chmod(CONFIG_FILE.parent, 0o700)

    flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
    fd = os.open(CONFIG_FILE, flags, 0o600)

    try:
        os.fchmod(fd, 0o600)
        with os.fdopen(fd, "w") as f:
            f.write("# OpenNotebook configuration\n")
            f.write(f"OPENNOTEBOOK_BASE_URL={self.base_url}\n")
            if self.api_key:
                f.write(f"OPENNOTEBOOK_API_KEY={self.api_key}\n")
            f.write(f"OPENNOTEBOOK_TIMEOUT={self.timeout}\n")
    except Exception:
        os.close(fd)
        raise

For stronger replacement semantics, write to a securely created temporary file in the same directory, set mode 0600, flush and synchronize it, and then atomically replace the destination.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The stated description presents the skill as a notebook client, but the documented behavior extends into model management, chat/session operations, embeddings, podcasts, and other administrative functions. This mismatch can mislead reviewers and users about the true attack surface, making it easier for sensitive or destructive capabilities to be granted under an apparently narrower purpose.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
所有 API 调用已封装到 `opennotebook.py` 脚本中。

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
92% confidence
Finding

This endpoint performs destructive deletion and includes a parameter that can broaden impact by deleting exclusive sources along with the notebook. In an agent skill, parameterized destructive actions are dangerous because prompt injection, ambiguous user instructions, or tool misuse could trigger irreversible data loss at larger scope than intended.

Content

Scanner excerpt · api_reference.md (reported line 62)May include surrounding context.

Delete Notebook

text
DELETE /api/notebooks/{notebook_id}
Query Parameters:
  - delete_exclusive_sources: boolean (delete sources only in this notebook)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
89% confidence
Finding

Removing a source from a notebook is a state-changing operation that could be abused by an agent acting on manipulated instructions or unclear user requests. While narrower than full deletion, it can still disrupt organization, downstream workflows, and data availability within the knowledge base.

Content

Scanner excerpt · api_reference.md (reported line 70)May include surrounding context.

Add/Remove Source

text
POST /api/notebooks/{notebook_id}/sources/{source_id}
DELETE /api/notebooks/{notebook_id}/sources/{source_id}

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
94% confidence
Finding

Direct source deletion is an irreversible destructive capability that can be triggered through a simple identifier parameter. In this knowledge-management context, sources may contain uploaded files or imported content, so misuse could cause significant data loss and break dependent search, chat, or transformation workflows.

Content

Scanner excerpt · api_reference.md (reported line 130)May include surrounding context.

Delete Source

text
DELETE /api/sources/{source_id}

Source Status

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
93% confidence
Finding

Note deletion is a destructive operation that an LLM-driven agent could invoke incorrectly if prompted by adversarial content or vague user instructions. Although narrower in scope than deleting notebooks or sources, it still causes irreversible loss of user-authored content.

Content

Scanner excerpt · api_reference.md (reported line 181)May include surrounding context.

Delete Note

text
DELETE /api/notes/{note_id}

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
83% confidence
Finding

Deleting chat sessions is a destructive operation, but typically affects conversation history rather than core repository content. It is still susceptible to accidental or prompt-induced misuse in an agent environment, though the likely impact is lower than deleting notebooks, sources, or credentials.

Content

Scanner excerpt · api_reference.md (reported line 317)May include surrounding context.

POST /api/chat/sessions GET /api/chat/sessions/{session_id} PUT /api/chat/sessions/{session_id} DELETE /api/chat/sessions/{session_id}

text

### Execute Chat

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
84% confidence
Finding

Deleting podcast episodes is a state-changing destructive capability that could remove generated content and associated artifacts. In an agent context, even secondary-content deletion can be abused through prompt injection or mistaken targeting if resource identifiers are selected automatically.

Content

Scanner excerpt · api_reference.md (reported line 347)May include surrounding context.

text
GET /api/podcasts/episodes
GET /api/podcasts/episodes/{episode_id}
DELETE /api/podcasts/episodes/{episode_id}
GET /api/podcasts/episodes/{episode_id}/audio

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill exposes broad capabilities including environment access, filesystem access, shell, network, and MCP interactions, but does not declare any explicit tool scope or permissions boundary in the manifest. This weakens reviewability and increases the chance an agent or user invokes the skill with more privilege than necessary, especially since it handles API keys and can modify remote data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation includes commands for delete, update, retry, rebuild, execute, and other state-changing operations without clearly warning that they can alter or remove local or remote data. In an agent context, terse command references may be copied or auto-invoked, increasing the risk of unintended destructive actions against notebooks, notes, sources, embeddings, or generated content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file describes notebook deletion, including optional deletion of exclusive sources, but provides no warning that the action may permanently remove user data. Under the markdown-specific SQP-2 criteria, destructive behaviors affecting user data should be disclosed to users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The file documents file upload, source download, and source deletion endpoints, but does not warn that uploaded content may contain sensitive data or that deletion removes stored user content. For markdown skill descriptions, behaviors affecting user data or privacy should be called out explicitly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The notes section includes an endpoint to delete notes but does not disclose that the action removes user-authored data. SQP-2 for markdown files requires warnings when behavior could affect user data or system integrity.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest describes the skill as an OpenNotebook client for notebooks, source files, notes, AI search, and transformation pipelines. This reference additionally exposes managing provider API credentials and testing them, which is a materially broader administrative capability not reflected in the stated description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Credential-management endpoints involve highly sensitive secrets, and documenting them without explicit handling guidance increases the chance that an agent or integrator will pass, log, or expose provider credentials insecurely. In an agent skill context, secret-bearing operations are more dangerous because LLM-driven tools can inadvertently surface or mishandle sensitive values.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The save() method writes OPENNOTEBOOK_API_KEY in plaintext to a predictable file under the user's home directory without setting restrictive file permissions or warning the user. On multi-user systems or misconfigured environments, other local users or processes may be able to read the credential, enabling unauthorized API access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The sources_upload function reads a local file and sends it over HTTP to the configured API endpoint. While uploading is part of the command's purpose, the code lacks any explicit disclosure in comments, docstrings, or user-facing output that local file contents will be transmitted to a server, which is relevant for user privacy and safety.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The client exposes model administration functions such as creation/deletion, default assignment, provider discovery/sync, and also settings and command/job administration elsewhere, but these higher-risk capabilities are not reflected in the stated skill purpose. This mismatch increases the chance that a caller grants trust appropriate for note/search features while unintentionally exposing operational control surfaces.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The upload path reads an arbitrary local file and transmits its contents to the configured remote service with no user-facing warning or confirmation in the code path. In an agent setting, this can enable unintended exfiltration of sensitive local files if upstream prompts or tool invocations are manipulated.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description presents the client as a knowledge-management tool, but the implemented surface also includes credential listing, creation, update, deletion, testing, and migration. Undisclosed administrative credential capabilities materially expand the power of the skill and can mislead users or higher-level agents into invoking sensitive operations they did not expect.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The credential migration endpoint can trigger bulk ingestion of secrets from environment or provider configuration, yet the client provides no warning, confirmation, or guardrail around this sensitive action. In a tool-using agent context, this raises the risk of unintentionally centralizing or exposing credentials beyond the user's expectations.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · test_integration.py (reported line 431)May include surrounding context.

python
]

        for cmd, desc in commands:
            result = subprocess.run(
                ["python3", str(cli_path)] + cmd,
                capture_output=True,
                text=True

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language strings that force a specific language/locale for usage instructions and runtime output. Under the stated policy, hard-coding a language without offering user choice or documenting a justified locale constraint is a policy violation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · test_opennotebook.py (reported line 210)May include surrounding context.

python
def run_cli(self, args):
        """运行 CLI 命令"""
        result = subprocess.run(
            ["python3", "opennotebook.py"] + args,
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · test_opennotebook.py (reported line 433)May include surrounding context.

python
failed = 0

    for cmd, desc in commands:
        result = subprocess.run(
            ["python3", "opennotebook.py"] + cmd,
            capture_output=True,
            text=True,

Static analysis

No suspicious patterns detected.