Back to skill

Security audit

librarian companion

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent local book-search companion, but it uses broad conversational triggers plus shell execution and an unsafe temporary file pattern that warrant review before installation.

Install only if you are comfortable with the skill searching your local Librarian indexes and running local shell/Python commands. Prefer narrowing triggers to explicit 'librarian ...' commands and fixing librarian.sh to use mktemp and direct array execution before using it with private libraries.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
librarian.sh:103
Finding

Predictable Temporary File Allows Symlink-Based File Overwrite

Content
View full analysis

Vulnerability Details

File Location: librarian.sh, lines 103–104
Vulnerability Type: Predictable temporary file and unsafe file creation
Risk Level: Medium

Vulnerable Code

bash
local tmp_json="/tmp/librarian-$$.json"
if ! eval "$cmd" 2>/dev/null > "$tmp_json"; then

Technical Analysis

The wrapper stores research output in a predictable PID-derived path under the shared /tmp directory. Shell redirection opens this path without exclusive creation, ownership validation, or symbolic-link protection.

A local attacker can anticipate or enumerate the process ID and create /tmp/librarian-<PID>.json as a symbolic link before the redirection occurs. The shell then follows the link and truncates or overwrites its target with the research process output.

Although eval is unnecessary and increases command-execution complexity, the command is generated using Bash %q escaping in the reviewed implementation. The confirmed vulnerability is therefore the unsafe temporary-file operation, not a demonstrated command-injection path.

Attack Path

  1. A local attacker identifies that the victim uses this Skill.
  2. The attacker predicts or enumerates a likely wrapper process ID.
  3. The attacker creates /tmp/librarian-<PID>.json as a symbolic link to a file writable by the victim.
  4. The victim invokes librarian.sh.
  5. Shell redirection follows the attacker-created symbolic link.
  6. The linked file is truncated and replaced with the research command's output.
  7. The wrapper subsequently processes and removes the temporary pathname, but this does not reverse corruption of the linked target.

Impact Assessment

Exploitation requires local filesystem access and sufficient timing or PID prediction. It does not independently grant elevated privileges.

An attacker can overwrite files writable by the account running the Skill. Depending on the selected target, this could cause:

...[truncated 354 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create temporary files atomically with mktemp rather than constructing a PID-based filename:

    bash
    local tmp_json
    tmp_json="$(mktemp "${TMPDIR:-/tmp}/librarian.XXXXXX")" || {
        echo "ERROR_TEMPFILE_CREATION"
        exit "$EXIT_BROKEN"
    }
    
  2. Register cleanup immediately so the file is removed on normal exit, errors, and signals:

    bash
    trap 'rm -f -- "$tmp_json"' EXIT HUP INT TERM
    
  3. Avoid serializing the command and executing it through eval. Build and execute a Bash array directly:

    bash
    local cmd=(
        python3 "$RESEARCH_PY" "$query"
    )
    
    if [[ "$scope_type" == "topic" ]]; then
        cmd+=(--topic "$scope_value")
    elif [[ "$scope_type" == "book" ]]; then
        cmd+=(--book "$scope_value")
    else
        echo "ERROR_INVALID_SCOPE"
        exit "$EXIT_BROKEN"
    fi
    
    cmd+=(--top-k "$top_k")
    
    if ! "${cmd[@]}" >"$tmp_json" 2>/dev/null; then
        echo "ERROR_EXECUTION_FAILED"
        exit "$EXIT_BROKEN"
    fi
    
  4. Apply restrictive permissions with umask 077 before creating the file if the search output may contain sensitive excerpts.

  5. Preserve validation exit codes before cleanup rather than relying on $? after rm, ensuring malformed output cannot be reported as success.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · README.md (reported line 33)May include surrounding context.

Verify:

bash
ls -la ~/.openclaw/skills/librarian
# Should point to ~/Documents/librarian/skill

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documented trigger patterns include very broad natural-language phrases such as 'research for', 'ask ... about', and 'can you check it against', which can match ordinary conversation and cause the skill to activate unexpectedly. In a skill that performs searches over local indexed books and influences assistant behavior, unintended activation can expose private library contents, produce confusing context switches, or trigger actions the user did not intend.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill explicitly instructs the agent to execute shell commands such as ./librarian.sh ..., python3 ..., and filesystem reads, but the manifest does not declare any permissions or allowed-tools scope. That mismatch weakens policy enforcement and increases the chance the runtime grants broader execution than intended or the skill is invoked without clear operator consent for command execution.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Several triggers are broad conversational phrases, especially research, research for, can you check it against, and ask (topic/book) about, which can match normal user dialogue unrelated to this skill. Unintended activation is risky here because the skill is capable of invoking shell-based local search commands and reading local metadata, so a casual phrase could launch tool use against user files without clear intent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The hard-stop protocol specifies fixed Portuguese user-facing responses such as "Não tem metadata" and "Não entendi". This imposes a language choice without indicating that the user can choose their preferred language, which conflicts with the language/locale policy for natural-language behavior.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

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

md
**1. Synthesize answer** (don't just list chunks)
   - Read all results
   - Extract key points
   - Write coherent paragraph(s)

**2. Cite sources with emojis**
   - 📕 = book citation

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

python
# Run research.py
    try:
        result = subprocess.run(
            cmd,
            cwd=str(LIBRARIAN_PATH),
            capture_output=True,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script emits user-facing status and error messages in Portuguese, such as 'Não achei resultados' and 'Sugestões', while the surrounding usage text is in English. This creates a language-policy issue because the skill imposes a specific locale on users without opt-in or configuration.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The main results display includes Portuguese-only labels like 'Achei', 'Fonte', and 'Fontes citadas'. Because the file does not provide a language selection mechanism or justify a region-specific constraint, this is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script executes a dynamically built command via eval and writes its output to /tmp/librarian-$$.json, but the user-facing interface only shows usage text and does not disclose these actions. The code also suppresses stderr, reducing visibility into what is being executed and written.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.