Back to skill

Security audit

Project- & Time-Capsules

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent project-archiving purpose, but its script can execute unintended shell commands and write or upload data with weak safeguards.

Review carefully before installing. Use only with trusted rclone remotes and non-sensitive project material, avoid secrets or regulated data, require explicit confirmation before uploads or memory changes, and do not use untrusted capsule names or files until the script removes shell=True, validates capsule names, and confines local staging paths.

Vulnerability Patterns
  • 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
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/kapsel.py:31
Finding

Arbitrary Command Execution Through Shell Command Injection

Content
View full analysis
/dev/null") summary, _ = run( f'rclone cat "{KAPSELN_REMOTE}/{name}/summary.md" 2>/dev/null' ) out, err = run( f'rclone copy "{LOCAL_TMP}/{name}" "{KAPSELN_REMOTE}/{name}/"' ) details, _ = run( f'rclone cat "{KAPSELN_REMOTE}/{name}/details.md" 2>/dev/null' ) context, _ = run( f'rclone cat "{KAPSELN_REMOTE}/{name}/context.md" 2>/dev/null' ) files, _ = run( f'rclone ls "{KAPSELN_REMOTE}/{name}/files/" 2>/dev/null' ) out, err = run( f'rclone copy "{filepath}" "{KAPSELN_REMOTE}/{name}/files/"' ) ``` The affected values originate from command-line arguments or environment variables: ```python KAPSELN_REMOTE = os.environ.get("KAPSEL_REMOTE", "gdrive:Kapseln") LOCAL_TMP = os.environ.get("KAPSEL_TMP", "/tmp/openclaw/kapseln") name = sys.argv[2] filepath = sys.argv[3] ``` ### Technical Analysis The `run` function passes a constructed string to `subprocess.run` with `shell=True`. Consequently, `/bin/sh` parses metacharacters and performs command substitution, variable expansion, redirection, and command chaining. Adding double quotes around an interpolated value does not make it safe. Sh ...[truncated 1790 chars]
Remediation
View remediation
/dev/null`; use `stderr=subprocess.DEVNULL` where suppression is genuinely required. 5. Check `returncode` instead of searching stderr for the word `error`. 6. Add tests using names and paths containing spaces, quotes, dollar signs, backticks, semicolons, and command substitutions to verify that none are interpreted by a shell. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/kapsel.py:74
Finding

Arbitrary File Write Through Capsule Name Path Traversal and Unsafe Temporary Paths

Content
View full analysis
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
scripts/kapsel.py:129
Finding

Indirect Prompt Injection Through Untrusted Cloud Capsule Content

Content
View full analysis
/dev/null') if not summary: print(f"Capsule '{name}' not found.") return print(f"## Capsule loaded: {name}\n") print("### Summary") print(summary) print("\n### Details") details, _ = run(f'rclone cat "{KAPSELN_REMOTE}/{name}/details.md" 2>/dev/null') print(details or "(no details)") print("\n### Technical Context") context, _ = run(f'rclone cat "{KAPSELN_REMOTE}/{name}/context.md" 2>/dev/null') print(context or "(no context)") files, _ = run(f'rclone ls "{KAPSELN_REMOTE}/{name}/files/" 2>/dev/null') if files: print("\n### Files") for line in files.splitlines(): parts = line.split(None, 1) if len(parts) == 2: print(f" - {parts[1]}") ``` The documented workflow explicitly directs an AI agent to load this material as project context: ```text Need old project knowledge — `summary` gives a quick refresher. If you need the full picture, use `load` to get all details and technical context. ``` ### Technical Analysis Capsule documents reside on an external rclone remote and may be modified independently of the reviewed skill package. The application treats retrieved Markdown as trusted project context and emits it verbatim into the agent-facing output. If an attacker gains write access to the remote, a shared capsule, or synchronized storage, they can place instruction-like text in `summary.md`, `details.md`, or `context.md`. An AI agent consuming the outpu ...[truncated 1758 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Warning
Location
SKILL.md:92
Finding

Unsafe Persistent Agent-Memory Modification Workflow

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (11)

Vague Triggers

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger conditions are extremely broad and match common phrases like 'save this project' or 'load the old project,' making accidental activation likely during ordinary project-management conversations. Because this skill can lead to file writes and cloud archival of project knowledge, over-triggering could cause unintended persistence, disclosure, or retrieval of sensitive data outside the user's actual intent.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This skill is supposed to manage archived project knowledge, but it exposes arbitrary shell-command execution via rclone command strings assembled from user input. In an agent setting, that broadens the tool from archive management into a general command-execution primitive, which is especially dangerous because capsule names and file paths may come from natural-language user requests.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The tool accepts attacker-influenceable parameters and passes them into subprocess.run with shell=True, enabling parameter abuse to become arbitrary command execution. In an agent context, this is particularly severe because a user can phrase a request that causes the agent to supply malicious capsule names or file paths, escaping the skill's intended boundaries.

Content

Scanner excerpt · scripts/kapsel.py (reported line 35)May include surrounding context.

python
def run(cmd):
    """Run a shell command and return (stdout, stderr)."""
    try:
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30)
        return result.stdout.strip(), result.stderr.strip()
    except subprocess.TimeoutExpired:
        return "", "Error: Command timed out after 30 seconds"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises shell, environment-variable, and file-write capabilities but does not declare any explicit tool scope or permission boundaries. In an agent setting, this increases the chance the agent invokes powerful operations implicitly, including writing local files and triggering rclone-backed uploads, without a clear trust boundary or user approval model.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill describes archiving project knowledge and files to cloud storage but does not prominently warn that this may upload sensitive internal information, credentials, client data, or code artifacts to a third-party provider. In this context, the omission is risky because the skill's core purpose is data export, and users may not realize the privacy, compliance, or retention implications before using it.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Remote storage location is controlled by environment variables, but the tool does not disclose the active remote or warn that project data will be read from and written to externally managed storage. In an agent workflow, hidden environment-based routing can send sensitive data to an unexpected account, bucket, or tenant.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The helper executes shell commands with shell=True, and multiple callers build those command strings from user-controlled capsule names, file paths, and environment-configured paths. This creates a direct command-injection surface where crafted input can break out of quoting and execute arbitrary OS commands under the agent's privileges.

Content

Scanner excerpt · scripts/kapsel.py (reported line 35)May include surrounding context.

python
def run(cmd):
    """Run a shell command and return (stdout, stderr)."""
    try:
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30)
        return result.stdout.strip(), result.stderr.strip()
    except subprocess.TimeoutExpired:
        return "", "Error: Command timed out after 30 seconds"

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest emphasizes cloud-backed project memory capsules, but create materializes directories and markdown files on the local filesystem under KAPSEL_TMP before uploading them. Local file creation may be an implementation detail in part, but here it is a persistent write behavior exposed through the skill that is broader than the user-facing description of archiving and reloading knowledge.

Content

No source excerpt is available for this finding.

Tainted flow: 'path' from os.environ.get (line 131, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
82% confidence
Finding

The file creation path is constructed from LOCAL_TMP and the capsule name, both effectively untrusted for security purposes. Without validation, a malicious capsule name such as one containing traversal sequences can redirect writes to unintended locations on the local filesystem.

Content

Scanner excerpt · scripts/kapsel.py (reported line 132)May include surrounding context.

python
("context.md", context),
    ]:
        path = f"{LOCAL_TMP}/{name}/{fname}"
        with open(path, "w") as f:
            f.write(content)

    out, err = run(f'rclone copy "{LOCAL_TMP}/{name}" "{KAPSELN_REMOTE}/{name}/"')

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill uploads project summaries, details, technical context, and files to remote cloud storage without presenting a user-facing warning or confirmation about external transmission. Because the stored material may include sensitive project knowledge, silent upload increases the risk of unintended data disclosure and privacy violations.

Content

No source excerpt is available for this finding.

Tainted flow: 'LOCAL_TMP' from os.environ.get (line 29, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
79% confidence
Finding

The code writes to a filesystem path derived from the environment variable KAPSEL_TMP combined with a user-controlled capsule name, without normalization or confinement checks. An attacker who can influence either value could cause writes outside the intended temp area or overwrite arbitrary files accessible to the process.

Content

Scanner excerpt · scripts/kapsel.py (reported line 195)May include surrounding context.

python
summary = summary.replace("Status: aktiv", f"Status: archived ({now})")

    os.makedirs(f"{LOCAL_TMP}/{name}", exist_ok=True)
    with open(f"{LOCAL_TMP}/{name}/summary.md", "w") as f:
        f.write(summary)
    run(f'rclone copy "{LOCAL_TMP}/{name}/summary.md" "{KAPSELN_REMOTE}/{name}/"')
    print(f"Capsule '{name}' archived ({now}).")

Static analysis

No suspicious patterns detected.