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## 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
## 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
Content
**Verify:**
```bash
ls -la ~/.openclaw/skills/librarian
# Should point to ~/Documents/librarian/skill
```
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Vague Triggers

Medium
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.

Lp3

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.

Vague Triggers

Medium
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.

Natural-Language Policy Violations

Medium
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.

Session Persistence

Medium
Category
Rogue Agent
Content
**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
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.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# Run research.py
    try:
        result = subprocess.run(
            cmd,
            cwd=str(LIBRARIAN_PATH),
            capture_output=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
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.

Natural-Language Policy Violations

Medium
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.

Missing User Warnings

Medium
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.

Static analysis

No suspicious patterns detected.