Back to skill

Security audit

paper claw

Security checks for vulnerabilities and agentic risk

Overview

This paper-digest skill is mostly purpose-aligned, but it needs Review because its example code can execute a Python script outside the reviewed skill package.

Install only if you are comfortable reviewing or fixing the package first. In particular, ensure the main script is packaged inside the skill directory, correct the SKILL_ROOT path handling, and require explicit confirmation before sending email or changing recipients/source configuration.

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
example.py:14
Finding

Execution of an Unverified Python Script Outside the Skill Directory

Content
View full analysis

Vulnerability Details

File Location: example.py, lines 14 and 31-38
Vulnerability Type: Execution across the packaged Skill trust boundary
Risk Level: Medium

Vulnerable Code:

python
# Skill root directory
SKILL_ROOT = Path(__file__).resolve().parents[1]
PRESETS_DIR = Path(__file__).resolve().parent / "presets"
python
cmd = ["python", str(SKILL_ROOT / "scripts" / "main.py")]

if day:
    cmd.extend(["--day", day])
elif start_date and end_date:
    cmd.extend(["--start-date", start_date, "--end-date", end_date])

result = subprocess.run(cmd, capture_output=True, text=True, cwd=SKILL_ROOT)

Technical Analysis

example.py is located at the root of the supplied Skill. Consequently, Path(__file__).resolve().parents[1] resolves to the parent of the Skill directory rather than the Skill directory itself. The fetch_papers() function then attempts to execute scripts/main.py beneath that external directory.

The audited package does not contain scripts/main.py. Therefore, the code delegates execution to a file that is outside the reviewed package and whose integrity is not established. Although command arguments are passed as an array and do not create direct shell injection, the executable script path crosses the Skill trust boundary.

This behavior is not necessary for the declared functionality. A paper-fetching implementation should be packaged within the Skill and resolved relative to its verified root.

Attack Path

  1. An attacker obtains write access to the parent directory of the installed Skill or causes the Skill to be installed beneath an attacker-controlled directory.
  2. The attacker creates scripts/main.py under that parent directory.
  3. An Agent or user invokes fetch_papers().
  4. SKILL_ROOT resolves to the external parent directory.
  5. subprocess.run() launches the attacker-controlled Python script.
  6. The script executes with the same opera ...[truncated 672 chars]
Remediation
View remediation

Remediation Suggestions

  1. Resolve the Skill root to the directory containing example.py:

    python
    SKILL_ROOT = Path(__file__).resolve().parent
    
  2. Package scripts/main.py inside the Skill rather than depending on an external sibling or parent path.

  3. Resolve and validate the target before execution:

    python
    script = (SKILL_ROOT / "scripts" / "main.py").resolve()
    if not script.is_relative_to(SKILL_ROOT.resolve()):
        raise ValueError("Script path escapes the Skill directory")
    if not script.is_file():
        raise FileNotFoundError(script)
    
  4. Use sys.executable instead of the generic python command to ensure the intended Python interpreter is used:

    python
    import sys
    cmd = [sys.executable, str(script)]
    
  5. Verify the integrity or signature of executable packaged components before invocation where the deployment model permits package modification.

  6. Run the Skill under a restricted operating-system account without access to unrelated credentials or sensitive files.

T09 · Insecure Skill Coding Practices

Note
Location
example.py:67
Finding

Path Traversal Through Unvalidated Date and Preset Identifiers

Content
View full analysis

Vulnerability Details

File Location: example.py, lines 67-83 and 133-137
Vulnerability Type: Improper validation of path components
Risk Level: Low

Vulnerable Code:

python
if format == "markdown":
    path = SKILL_ROOT / "content" / "posts" / f"{date}-arxiv-audio-digest.md"
    if path.exists():
        return {"content": path.read_text(encoding="utf-8"), "format": "markdown"}

elif format == "json":
    path = SKILL_ROOT / "data" / "processed" / f"{date}.json"
    if path.exists():
        data = json.loads(path.read_text(encoding="utf-8"))
        return {"content": data, "format": "json"}

elif format == "summary":
    path = SKILL_ROOT / "data" / "processed" / f"{date}.json"
    if path.exists():
        data = json.loads(path.read_text(encoding="utf-8"))
python
preset_path = PRESETS_DIR / f"{preset_id}.json"
if not preset_path.exists():
    return None

return json.loads(preset_path.read_text(encoding="utf-8"))

Technical Analysis

The externally supplied date and preset_id values are interpolated directly into filesystem paths. The implementation does not reject path separators, normalize and validate the resulting path, or confirm that the resolved file remains beneath the intended base directory.

The schema in tools.json documents date formatting and allowlists preset identifiers, but these controls are not enforced by the Python functions themselves. Direct callers of get_digest_content() and get_preset() can supply values containing ../ components.

The automatically appended filename suffixes constrain which external files can be reached. For example, the JSON branches can primarily target files whose resulting names end in .json. Nevertheless, suitably located JSON or digest files outside the intended directories can be read and returned.

Attack Path

  1. An untrusted caller gains the ability to invoke the Python API directly or ...[truncated 1033 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse dates strictly instead of treating them as arbitrary path fragments:

    python
    from datetime import datetime
    
    parsed = datetime.strptime(date, "%Y-%m-%d")
    safe_date = parsed.strftime("%Y-%m-%d")
    
  2. Allowlist preset identifiers from trusted preset metadata or a fixed set:

    python
    allowed_presets = {
        "speech_audio",
        "nlp",
        "computer_vision",
        "general_ai",
    }
    if preset_id not in allowed_presets:
        raise ValueError("Invalid preset identifier")
    
  3. Add a reusable resolved-path containment check:

    python
    def safe_child(base: Path, filename: str) -> Path:
        base = base.resolve()
        candidate = (base / filename).resolve()
        if not candidate.is_relative_to(base):
            raise ValueError("Path escapes the permitted directory")
        return candidate
    
  4. Reject absolute paths, path separators, null bytes, and traversal components before constructing a filename.

  5. Enforce validation in the Python implementation even when framework-level schemas are present, because direct callers can bypass tool-schema checks.

  6. Apply least-privilege filesystem permissions so the Agent cannot read unrelated configuration, credential, or user-data files.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
Findings (16)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

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

View papers by category

cat data/processed/2026-03-10.json | jq '.grouped.ASR'

Reset state and re-fetch

python scripts/reset_state.py python scripts/main.py --day 2026-03-10

text

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · tools.json (reported line 398)May include surrounding context.

json
}
  ],
  "config": {
    "env_file": ".env",
    "config_dir": "config",
    "output_dir": "content/posts",
    "data_dir": "data/processed"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill documents capabilities that read files, write configuration/state, and execute shell commands, but it does not declare any explicit tool scope or permission boundaries. In agent environments, this increases the risk of over-broad execution because consumers cannot tell up front that running the skill may modify local files or invoke system commands.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The workflow documentation says email is automatically sent, but the skill description and execution guidance do not prominently warn that running the main workflow can transmit generated content to configured recipients. This is a meaningful side effect because an agent or user could trigger external communication and possible data disclosure without realizing it.

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 · example.py (reported line 38)May include surrounding context.

python
elif start_date and end_date:
        cmd.extend(["--start-date", start_date, "--end-date", end_date])
    
    result = subprocess.run(cmd, capture_output=True, text=True, cwd=SKILL_ROOT)
    
    # Parse output to find generated files
    output = result.stdout + result.stderr

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This example exposes a persistent reconfiguration path that writes to the skill's default configuration on disk, changing sources and classification behavior beyond a transient fetch/summarize operation. In an agent setting, that means a caller can silently alter future runs and steer what content is collected or how it is categorized, creating integrity and persistence risks.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The code provides an unjustified persistent reconfiguration mechanism relative to the paper-processing purpose by allowing presets to overwrite core defaults on disk. This increases danger in agent environments because one invocation can alter all subsequent behavior, enabling durable tampering rather than a one-time action.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The function persistently rewrites recipients.json, allowing modification of who receives future email digests. Even if intended functionality includes email delivery, exposing broad recipient editing in an example utility creates a state-changing capability that could redirect notifications or add unauthorized recipients without adequate safeguards.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The function writes personal contact information to a persistent recipients.json file without any user-facing warning, consent flow, or minimization controls. This creates privacy and governance risk because email addresses and names may be stored unexpectedly, exposed to other local users/processes, or retained longer than intended.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Although multiple languages are supported, the fetch_papers tool defaults the output language to "zh". A forced default locale in a general-purpose skill can be a policy issue when users are not explicitly offered or prompted for their language preference.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill exposes an email-sending action that can transmit generated digest content and recipient information to external parties, but the manifest does not warn that data leaves the local/system boundary. In an agent setting, this increases the risk of unintended exfiltration of research content, recipient addresses, or sensitive summaries if invoked without explicit user awareness.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The preset workflow states that apply_preset automatically updates config/default.json, but it does not clearly warn users that invoking it modifies local configuration files. In an agent setting, undocumented file mutation can lead to unintended persistent state changes and surprise reconfiguration.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This JSON manifest describes the skill as "Broad AI/ML research covering multiple domains," which is extremely wide in scope and does not define clear activation boundaries or exclusions. For a manifest file, this lack of specificity can make it unclear when the skill should be selected versus more specialized AI-related skills.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

This JSON manifest includes the description "Broad AI/ML research covering multiple domains," which is highly general and lacks clear scope boundaries. In a manifest context, such broad wording can overlap with many common AI-related requests and makes it unclear when this preset should be selected versus more specific presets.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This manifest embeds multilingual labels, including Japanese, but there is no natural-language indication of how locale is selected or whether users can opt into a preferred language. Under the policy rule, forcing or implicitly assuming a locale without documented choice can be a language/locale policy concern.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

This manifest includes broad invocation descriptions such as "Configure data sources and categories" and similar update/configure actions elsewhere, without negative examples or contextual constraints. In a manifest file, such generic phrasing can overlap with common user requests and make unintended skill invocation more likely.

Content

No source excerpt is available for this finding.