Back to skill

Security audit

Bookmarks

Security checks for vulnerabilities and agentic risk

Overview

This bookmark skill has a coherent purpose, but it needs review because it runs an unbundled external Python script and can persist full assistant replies from session history.

Review before installing. Confirm that bookmark.py is bundled or otherwise fixed to a trusted, contained path, and understand that replying /save to an assistant message may retrieve and store the full assistant response from session history, not just the visible excerpt.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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 (2)

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/handler.py:20
Finding

Execution of an Unbundled and Externally Replaceable Python Script

Content
View full analysis

Vulnerability Details

File Location: scripts/handler.py, lines 20-26
Vulnerability Type: Execution of an untrusted local tool outside the audited project
Risk Level: High

Vulnerable Code

python
BOOKMARK_PY = Path(__file__).parent.parent.parent.parent / "scripts" / "bookmark.py"

def run_bookmark(*args):
    """Run bookmark.py with given args and return (stdout, stderr, rc)."""
    cmd = [sys.executable, str(BOOKMARK_PY)] + list(args)
    result = subprocess.run(cmd, capture_output=True, text=True)
    return result.stdout, result.stderr, result.returncode

Technical Analysis

The handler constructs the path to bookmark.py by traversing four parent directories from scripts/handler.py. In the supplied project layout, this resolves to /tmp/scripts/bookmark.py, which is outside the audited project directory.

The referenced script is not included in the supplied package, despite SKILL.md describing it as part of the Skill. Every bookmark operation invokes this external file using the current Python interpreter. Although arguments are passed as a list and are not directly vulnerable to shell injection, the executable Python source itself is unaudited and externally replaceable.

This creates a local tool-hijacking boundary: a file placed at the expected external path is treated as a legitimate project component and executed without path containment, ownership, permission, or integrity validation.

Attack Path

  1. An attacker obtains the ability to create or replace /tmp/scripts/bookmark.py, such as through another process operating in the shared temporary directory.
  2. The attacker writes a malicious Python payload to that location.
  3. A user invokes any supported bookmark operation, such as /save, /save list, or /save search.
  4. handler.py constructs a command using sys.executable and the external script path.
  5. Python executes the attacker-controlled script with t ...[truncated 573 chars]
Remediation
View remediation

Remediation Suggestions

  • Include bookmark.py within the audited Skill package instead of resolving it from an external directory.

  • Resolve the bundled script relative to the handler without upward traversal:

    python
    BOOKMARK_PY = Path(__file__).resolve().with_name("bookmark.py")
    
  • Resolve and validate the path before execution, ensuring it remains under the expected package directory.

  • Fail closed if the script is missing, is a symbolic link, has unexpected ownership or permissions, or resolves outside the Skill directory.

  • Where practical, import a trusted internal Python module and call its functions directly rather than spawning a separate interpreter.

  • Protect packaged files from modification and verify their integrity when deployed in environments where local replacement is possible.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:42
Finding

Overbroad Session-History Retrieval with Ambiguous Message Matching

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 42-58
Vulnerability Type: Excessive access to conversation history and unintended sensitive-data persistence
Risk Level: Medium

Vulnerable Skill Instructions

markdown
## Workflow

1. Detect `/save` message (standalone or reply).
2. **If replying to assistant message**: fetch full text from session history to avoid truncation, pass via `--full-content`.
3. Parse sub-command and arguments.
4. Run appropriate `bookmark.py` subcommand via exec.
5. Return formatted results to user.

## Save behavior

- **Reply to assistant message**: retrieve full response from session history, save complete text via `--full-content` override
- **Reply to user/other message**: capture the replied-to message text as content (may be truncated if long — recommend inline `/save <text>` for long messages)
- **Inline mode**: use the text after `/save` as content
- **Auto-tags**: extract from content using keyword heuristics
- **Manual tags**: user can append `#tag1 #tag2` to note

## Full-Content Retrieval

When replying `/save` to an assistant (cloudybot) message, the skill retrieves the full assistant response from session history instead of using the truncated context snippet. This is done by:
1. Detecting `[reply target] cloudybot` in the context
2. Fetching session history via `sessions_history`
3. Matching the assistant message by its truncated prefix
4. Passing the full text via `handler.py save-reply --full-content "..."`

Technical Analysis

The Skill directs the Agent to retrieve session history to reconstruct one replied-to assistant message. Accessing broader session history exceeds the minimum data access required for ordinary bookmark operations.

The selected message is matched using a truncated textual prefix rather than an immutable session and message identifier. Prefix matching is not guaranteed to be unique. Multiple assistant mess ...[truncated 1675 chars]

Remediation
View remediation

Remediation Suggestions

  • Retrieve only the explicitly replied-to message using immutable message and session identifiers.
  • Do not scan broader session history or match messages by truncated textual prefixes.
  • If the platform cannot retrieve one exact message, save the visible reply content or require explicit user confirmation before accessing history.
  • Scope every history request to the current authorized session and minimum required time range.
  • Verify that exactly one message matches before saving; fail closed when the target is ambiguous.
  • Present the resolved message identity or a preview to the user before persisting full content.
  • Avoid storing unrelated metadata or surrounding history in memory/bookmarks.md.
  • Apply access controls to bookmark listing, searching, showing, and deletion so persisted content is available only to its authorized owner.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes shell-backed scripts (bookmark.py, handler.py) but declares no explicit tool scope or permissions boundary. That creates an authorization gap: an agent may run shell capabilities more broadly than the skill description makes clear, increasing the chance of unintended command execution or misuse if inputs are not tightly controlled downstream.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill silently retrieves full assistant message text from session history and stores it when a user replies /save, but the user-facing description does not clearly warn that truncated visible content may expand into a larger historical capture. This can lead to unintended retention of sensitive data, prompts, secrets, or private context that the user did not realize would be fetched and persisted.

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 · scripts/handler.py (reported line 29)May include surrounding context.

python
def run_bookmark(*args):
    """Run bookmark.py with given args and return (stdout, stderr, rc)."""
    cmd = [sys.executable, str(BOOKMARK_PY)] + list(args)
    result = subprocess.run(cmd, capture_output=True, text=True)
    return result.stdout, result.stderr, result.returncode

Static analysis

No suspicious patterns detected.