Back to skill

Security audit

Little Steve Task Manager

Security checks for vulnerabilities and agentic risk

Overview

This is a small local task manager whose file writes are expected, with some local hardening issues but no evidence of deception, exfiltration, or unsafe remote behavior.

Install only if you are comfortable with a local file-backed task list. Avoid running it as a privileged user, keep the skill data directory writable only by trusted accounts, and do not store secrets or highly sensitive operational details in task titles until the temporary-file and output-escaping issues are fixed.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/task.sh:104
Finding
Predictable Temporary File Allows Symlink-Based File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/task.sh:93-105` and `scripts/task.sh:139-151` **Vulnerability Type**: Predictable temporary file and unsafe symbolic-link handling **Risk Level**: Medium ### Vulnerable Code ```bash jq --arg title "$title" --arg priority "$priority" --arg due "$due" --arg tags "$tags" --arg now "$now" --argjson id "$id" --argjson w "$w" ' .tasks += [{ id:$id, title:$title, status:"open", priority:$priority, priorityWeight:$w, due:$due, tags:($tags|split(",")|map(gsub("^[[:space:]]+|[[:space:]]+$";"")|select(length>0))), createdAt:$now, updatedAt:$now }] | .nextId += 1 ' "$DB" > "$DB.tmp" && mv "$DB.tmp" "$DB" ``` The update operation uses the same predictable path: ```bash jq --argjson id "$id" --arg status "$status" --arg priority "$priority" --arg due "$due" --arg title "$title" --arg now "$now" --argjson w "$w" ' .tasks |= map(if .id==$id then .status = (if $status=="" then .status else $status end) | .priority = (if $priority=="" then .priority else $priority end) | .priorityWeight = (if $priority=="" then .priorityWeight else $w end) | .due = (if $due=="" then .due else $due end) | .title = (if $title=="" then .title else $title end) | .updatedAt = $now else . end) ' "$DB" > "$DB.tmp" && mv "$DB.tmp" "$DB" ``` ### Technical Analysis Both database mutation paths write to the fixed filename `data/tasks.json.tmp`. Shell output redirection follows symbolic links. Consequently, a local attacker who can write to the `data` directory can pre-create `tasks.json.tmp` as a symbolic link to another file. When a more privileged user or automated Agent invokes an `add`, `update`, or `done` operation, the shell opens and truncates the symbolic-link target before `jq` executes. The generated JSON is then written to that target. The subsequent `mv` does not undo the corruption. The fixed temporary filename also makes concurrent operations unsafe. Tw ...[truncated 1342 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create a unique temporary file in the database directory with `mktemp`, for example: ```bash tmp="$(mktemp "$BASE_DIR/data/.tasks.json.XXXXXX")" trap 'rm -f -- "$tmp"' EXIT jq ... "$DB" > "$tmp" chmod 600 "$tmp" mv -- "$tmp" "$DB" trap - EXIT ``` - Keep the temporary file in the same filesystem as the database so the final rename remains atomic. - Never reuse a predictable temporary filename. - Validate that the database directory and database are not symbolic links when the deployment trust model requires this protection. - Add an exclusive lock, such as `flock`, around the complete read-modify-write sequence to prevent concurrent lost updates. - Restrict write access to the project and `data` directories to trusted accounts. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/task.sh:104
Finding
Database Permissions Are Not Preserved After Task Updates<![CDATA[ ## Vulnerability Details **File Location**: `scripts/task.sh:7-16`, `scripts/task.sh:104`, and `scripts/task.sh:150` **Vulnerability Type**: Insecure local data-file permissions **Risk Level**: Low ### Vulnerable Code The database receives restrictive permissions only when it is initially created: ```bash init_db(){ if [[ ! -f "$DB" ]]; then mkdir -p "$(dirname "$DB")" cat > "$DB" <<JSON {"tasks":[],"nextId":1} JSON chmod 600 "$DB" fi } ``` Each mutation replaces it with a newly created file without setting restrictive permissions: ```bash ' "$DB" > "$DB.tmp" && mv "$DB.tmp" "$DB" ``` The same replacement pattern is used in the update path: ```bash ' "$DB" > "$DB.tmp" && mv "$DB.tmp" "$DB" ``` ### Technical Analysis The script applies mode `0600` only when `tasks.json` does not exist. During every subsequent add or update operation, shell redirection creates `tasks.json.tmp` using permissions derived from the process umask. The script then moves that new file over the original database. A common umask of `022` creates the temporary file with mode `0644`. After the rename, the database can therefore become readable by other local users even if the original database was mode `0600`. The script also does not correct the permissions of the database bundled with the project or of an existing database created outside `init_db`. ### Attack Path 1. A user runs the Skill in an environment with a permissive umask, such as `022`. 2. An `add`, `update`, or `done` command creates `data/tasks.json.tmp`, commonly with mode `0644`. 3. The script moves the temporary file over `data/tasks.json`. 4. Another local account with directory traversal access reads the newly world-readable or group-readable database. 5. Task titles, due dates, statuses, tags, and operational project details are disclosed. ### Impact Assessment No additional execution privileges are obtained. The impact is local confidentiality loss within the host: other users m ...[truncated 333 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set a restrictive umask near the beginning of the script: ```bash umask 077 ``` - Explicitly apply mode `0600` to every temporary database file before renaming it. - Verify and repair the permissions of an existing `tasks.json` during initialization rather than applying permissions only when the file is first created. - Use a unique temporary file and atomic rename while preserving ownership and intended mode. - Restrict the `data` directory itself, such as with mode `0700`, when task data is intended to be private to one user. - Add a regression test that performs a mutation under umask `022` and verifies that the resulting database remains mode `0600`. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/task.sh:61
Finding
Unsanitized Task Titles Permit Terminal and Display Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/task.sh:61-65` and `scripts/task.sh:181-185` **Vulnerability Type**: Terminal control-sequence and multiline output injection **Risk Level**: Low ### Vulnerable Code Title validation enforces only a maximum length: ```bash validate_title(){ if [[ ${#1} -gt 500 ]]; then echo "error: --title exceeds 500 char limit" >&2; exit 1 fi } ``` Titles are later emitted as raw text: ```bash | .[] | "[\(.status)][\(.priority)] #\(.id) \(.title)" + (if .due=="" then "" else " (due: \(.due))" end) + (if (.tags|length)>0 then " tags:" + (.tags|join(",")) else "" end) ' "$DB" ``` ### Technical Analysis A task title may contain newlines, carriage returns, ANSI escape sequences, bidirectional-text controls, and other non-printing characters because `validate_title` checks only its length. The list operation uses `jq -r`, which prints the resulting string without JSON escaping. An attacker-controlled title can therefore inject additional apparent task lines, overwrite terminal text, change colors, conceal content, create misleading bidirectional output, or otherwise manipulate how the task list appears to a user or downstream Agent. This is an output-presentation vulnerability, not shell command injection. For example, the bundled title `$(rm -rf /)` remains inert because it is passed to `jq` as JSON data and is never evaluated by the shell. ### Attack Path 1. The attacker submits a task title containing newline characters, ANSI terminal escapes, carriage returns, or bidirectional controls. 2. The script accepts and stores the title because it is no longer than 500 characters. 3. A user or Agent invokes `task.sh list`. 4. `jq -r` writes the title’s control characters directly to the terminal or IM output channel. 5. The crafted title forges displayed records, hides legitimate information, or manipulates terminal presentation. 6. A user or automation component may make an incorrect decision based ...[truncated 563 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Reject ASCII control characters, including newlines, carriage returns, and escape characters, when validating titles. - Reject or visibly escape Unicode bidirectional override and isolation controls unless they are explicitly required. - Normalize titles to a documented Unicode normalization form. - Escape untrusted values for the target output channel rather than assuming terminal output, IM output, and logs share the same safety rules. - For terminal output, render control characters as visible escaped sequences such as `\n` and `\u001b`. - If machine-readable consumption is required, provide a separate JSON output mode instead of parsing human-readable lines. - Add tests using multiline titles, ANSI escape sequences, carriage returns, and bidirectional controls. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
},
    {
      "id": 12,
      "title": "$(rm -rf /)",
      "status": "cancelled",
      "priority": "P2",
      "priorityWeight": 2,
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
},
    {
      "id": 12,
      "title": "$(rm -rf /)",
      "status": "cancelled",
      "priority": "P2",
      "priorityWeight": 2,
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
cat > "$DB" <<JSON
{"tasks":[],"nextId":1}
JSON
    chmod 600 "$DB"
  fi
}
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Low
Confidence
84% confidence
Finding
This is a markdown file, so missing-warning review applies to documented behaviors that may affect user data or system integrity. The README states that the skill supports automatic status updates and identifies persistent data files, but it does not warn users that task data and settings will be modified on disk.

Natural-Language Policy Violations

Low
Confidence
70% confidence
Finding
Policy review applies to all file types and includes language/locale violations when a skill forces a specific language without user opt-in. This README includes a full Chinese section in addition to English, but does not clarify whether the skill's interaction language is selectable or whether Chinese output is optional.

Natural-Language Policy Violations

Low
Confidence
79% confidence
Finding
The description is explicitly duplicated in English and Chinese, and the document provides full parallel operating instructions in both languages. While bilingual support is often positive, the file does not clarify whether the agent should choose language based on user preference, which can create an implicit locale behavior without opt-in.

Missing User Warnings

Low
Confidence
88% confidence
Finding
This markdown file states that the skill uses `tasks.json` and `settings.json`, and later shows add/update/done commands that imply persistent writes. However, it does not include any user-facing warning that using the skill changes local task data on disk, which is relevant to user data integrity for markdown-scoped warning checks.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
This JSON task file contains multiple task titles written in Chinese, including mojibake-encoded Chinese text, with no indication that language selection is configurable or intentionally region-scoped. Under the language/locale policy rule, fixed-language content can be a policy concern when a skill or related asset does not offer user opt-in or document the locale constraint.

Static analysis

No suspicious patterns detected.