Back to skill

Security audit

Idiom Dictionary

Security checks for vulnerabilities and agentic risk

Overview

The skill presents itself as a Chinese idiom dictionary, but one bundled command is a generic local data logger that persistently records arguments without clear disclosure.

Install only if you are comfortable with a local shell utility that writes persistent files under the configured idiom-dictionary data directory. Avoid passing secrets as command arguments, keep IDIOM_DICTIONARY_DIR pointed at a private user-owned directory, and treat the generic add/list/export behavior as broader than the documented idiom dictionary features.

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
scripts/idiom.sh:3
Finding

Unquoted User Input Permits Word Splitting and Pathname Expansion

Content
View full analysis
/dev/null || true; INPUT="$*" python3 -c ' import sys,hashlib cmd=sys.argv[1] if len(sys.argv)>1 else "help" inp=" ".join(sys.argv[2:]) # ... ' "$CMD" $INPUT ``` ### Technical Analysis The script combines all remaining arguments into `INPUT` and later expands `$INPUT` without double quotes. Bash consequently performs word splitting and pathname expansion on the value before invoking Python. This processing occurs even when a caller originally quoted a wildcard. For example, an argument supplied as the literal `'*'` can be expanded by line 31 into filenames from the script's current working directory. The resulting filenames are passed to Python as search terms. If no idiom matches, the Python code includes the reconstructed input in its response: ```python if not found: print(" No match for: {}. Try a Chinese character or English keyword.".format(key)) ``` Shell metacharacters introduced through the variable are not reparsed as shell syntax, so this is not direct command injection. However, unintended wildcard expansion and argument splitting can expose local filenames and alter command behavior. ### Attack Path 1. An attacker causes the skill to execute an idiom search with a literal wildcard, such as `idiom.sh search '*'`. 2. The invoking shell preserves the wildcard because it is quoted. 3. The script stores the wildcard in `INPUT`. 4. The unquoted `$INPUT` expansion on line 31 performs pathname expansion in the script's working directory. 5. Matching local filenames are passed to Python as individual arguments. 6. Python joins those arguments and may display the filenames in the “No match” output. ### Impact Assessment Successful exploitation can disclose names of files and directories visible from the process's current working dire ...[truncated 402 chars]
Remediation
View remediation
/dev/null || true python3 -c ' import sys cmd = sys.argv[1] if len(sys.argv) > 1 else "help" inp = " ".join(sys.argv[2:]) # ... ' "$CMD" "$@" ``` Additional hardening measures: 1. Do not serialize arguments through `INPUT="$*"` when the original argument boundaries can be retained. 2. Double-quote every shell variable expansion unless word splitting or glob expansion is explicitly required. 3. Run ShellCheck in continuous integration and treat findings such as SC2086 as failures. 4. Add tests using literal inputs such as `*`, `?`, whitespace, filenames beginning with `-`, and empty arguments. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/script.sh:5
Finding

Configurable Data Directory Allows Symlink-Following File Writes

Content
View full analysis
> "$DATA_DIR/history.log"; } ``` ```bash cmd_add() { echo "$(date +%Y-%m-%d) $*" >> "$DB"; echo " Added: $*" _log "add" "${1:-}" } ``` ### Technical Analysis The environment variable `IDIOM_DICTIONARY_DIR` controls the directory used for persistent files. The script creates or opens predictable names—`data.log` and `history.log`—with the shell append operator without validating: - Whether `DATA_DIR` is a symbolic link. - Whether either destination file is a symbolic link. - Whether the directory and destination files are owned by the executing user. - Whether the directory is writable by untrusted users. - Whether the destinations are regular files. Shell redirection follows symbolic links. If an attacker can prepare the configured directory or replace one of the predictable files with a symbolic link, subsequent commands append content to the symlink target. The write remains subject to the permissions of the user executing the script. The vulnerability does not bypass operating-system access controls by itself. ### Attack Path 1. An attacker creates or controls a directory accessible to the victim. 2. The attacker creates a symbolic link such as: ```bash ln -s /path/to/victim-writable-file /attacker/controlled/data.log ``` Alternatively, the attacker creates `history.log` as a symbolic link. 3. The victim runs the utility with the attacker-prepared directory: ```bash IDIOM_DICTIONARY_DIR=/attacker/controlled idiom-dictionary add 'attacker-controlled text' ``` 4. `mkdir -p` accepts the existing directory wi ...[truncated 1077 chars]
Remediation
View remediation
&2 exit 1 fi if [[ -e "$DB" && ( -L "$DB" || ! -f "$DB" ) ]]; then echo "Unsafe database file" >&2 exit 1 fi HISTORY="$DATA_DIR/history.log" if [[ -e "$HISTORY" && ( -L "$HISTORY" || ! -f "$HISTORY" ) ]]; then echo "Unsafe history file" >&2 exit 1 fi ``` Because separate validation and opening operations may be vulnerable to a time-of-check/time-of-use race in an attacker-writable directory, stronger hardening should include: 1. Require the data directory to be owned by the current effective user and not writable by group or others. 2. Refuse directories located in untrusted shared paths. 3. Create files atomically with exclusive and no-follow semantics through a helper implemented in a language that exposes `O_CREAT`, `O_EXCL`, and `O_NOFOLLOW`. 4. Verify with `fstat` after opening that the destination is a regular file owned by the expected user. 5. Keep file descriptors open for writes instead of repeatedly resolving predictable paths. 6. Document that `IDIOM_DICTIONARY_DIR` must reference a private, user-owned directory. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest description and skill content present the skill as operating in Chinese only, with no indication that users may choose another language or that the locale restriction is optional. This is a natural-language policy concern because the skill appears to impose a specific language by default rather than offering user choice.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The header and help text identify the script as 'idiom-dictionary', which implies dictionary-oriented functionality, but the documented commands and implementation operate as a generic multi-purpose utility that stores arbitrary entries in a local log file. This is not merely incomplete documentation: the naming and presented identity contradict the actual behavior of the code.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script persistently records user-supplied command arguments into history.log without clear disclosure in the help text. Users may pass sensitive content as arguments, and those values will remain on disk under the user's data directory, creating a local privacy and credential exposure risk to other processes, backups, or anyone with access to the account.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill’s natural-language content is fixed to a specific language/locale pairing: Chinese idioms with English explanations. Under the stated policy, forcing a specific language without user opt-in can be a locale-policy issue, and this file does not indicate any option to choose another language or locale.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.