Back to skill

Security audit

Wiki Entry Skill

Security checks for vulnerabilities and agentic risk

Overview

This skill has a clear wiki-maintenance purpose, but its bundled scripts allow overbroad local command execution and writes outside the intended vault boundary.

Install only in a high-trust local vault and run under least filesystem privileges. Before broader use, patch or restrict the raw --audit-cmd shell execution, reject absolute and ../ paths, canonicalize every target under the configured vault, and treat note content and wikilinks as untrusted input. Keep the vault in version control or backups because the skill intentionally rewrites and moves files.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/wiki_entry_step_checkpoint.sh:94
Finding
Arbitrary Shell Command Execution Through Checkpoint Audit Commands<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wiki_entry_step_checkpoint.sh:94-101` **Vulnerability Type**: OS command injection through dynamic shell evaluation **Risk Level**: High ### Vulnerable Code ```bash if [ "$STATUS" = "done" ]; then prev=1 while [ "$prev" -lt "$STEP" ]; do s=$(get_status "$prev") if [ "$s" != "done" ]; then echo "❌ 防跳步: Step $STEP 不能标记 done,因为 Step $prev 当前是 $s" exit 1 fi prev=$((prev + 1)) done if [ -n "$AUDIT_CMD" ]; then echo "[micro-audit] $AUDIT_CMD" bash -lc "$AUDIT_CMD" rc=$? if [ "$rc" -ne 0 ]; then echo "❌ micro-audit 失败,Step $STEP 不能标记 done" exit 2 fi else echo "⚠️ Step $STEP 标记 done 但未提供 --audit-cmd" fi fi ``` ### Technical Analysis The `--audit-cmd` argument is accepted as an unrestricted string and passed directly to: ```bash bash -lc "$AUDIT_CMD" ``` This invokes a login shell and interprets all shell metacharacters, substitutions, pipelines, redirections, and compound commands contained in the argument. Quoting the variable at this invocation does not make the command safe because `bash -c` intentionally parses its contents as shell syntax. The interface is more powerful than required for the documented micro-audit operations. The examples only require fixed checks such as testing that a file exists or searching for a known marker, but the implementation permits arbitrary commands. If an untrusted note, generated workflow value, prompt, or operator-controlled input influences the audit command, it can convert a checkpoint operation into arbitrary code execution. ### Attack Path 1. An attacker causes malicious text to influence the audit operation selected by the Agent. 2. The resulting command is supplied to the checkpoint script, for example: ```bash --audit-cmd "legitimate_check; attacker_command" ``` 3. The script reaches a `done` checkpoint after previous steps are marked complete. 4. `bash -lc` parses a ...[truncated 955 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the free-form `--audit-cmd` interface. 2. Replace it with fixed audit types, such as: ```bash --audit-type file-exists --path "Knowledge/example.md" --audit-type contains-fixed --path "Knowledge/example.md" --value "marker" ``` 3. Invoke utilities directly with argument arrays rather than through `bash -c`: ```bash test -f "$validated_path" grep -Fq -- "$expected_value" "$validated_path" ``` 4. Canonicalize every supplied path and verify that it remains inside the configured vault. 5. Use an explicit allowlist of supported audit operations. 6. Reject shell metacharacters only as defense in depth; do not depend on filtering as the primary fix. 7. Run checkpoint validation with the minimum filesystem and network privileges available. 8. Add regression tests proving that values containing `;`, `|`, `$()`, backticks, redirections, and newlines are treated as data and never executed. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/wiki_entry_meta_writeback.sh:60
Finding
Missing Vault Confinement Allows Modification or Relocation of Files Outside the Vault<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/wiki_entry_meta_writeback.sh:60-80, 114-124, 169-218` - `scripts/wiki_entry_content_write.sh:23-28, 173-190, 266` - `scripts/wiki_entry_status_update.sh:17-22, 47, 95-113` - `scripts/wiki_entry_mv_graduated.sh:33-36, 84` - `scripts/_shared/index_update.sh:89-98, 191-196` **Vulnerability Type**: Path traversal, unrestricted absolute paths, and insufficient filesystem authorization **Risk Level**: High ### Vulnerable Code #### Metadata writer ```bash abs_path() { local p="$1" case "$p" in /*) printf '%s' "$p" ;; *) printf '%s/%s' "$VAULT" "$p" ;; esac } WIKI="$(abs_path "$WIKI_REL")" SOURCE_DOC="$(abs_path "$SOURCE_DOC_REL")" INDEX_FILE="$(abs_path "$INDEX_REL")" if [ ! -f "$WIKI" ]; then echo "❌ Wiki 不存在: $WIKI" exit 1 fi if [ ! -f "$SOURCE_DOC" ]; then echo "❌ source doc 不存在: $SOURCE_DOC" exit 1 fi ``` The resulting paths are later replaced: ```bash awk -v row="$SOURCE_ROW" ' BEGIN{in_tbl=0;inserted=0} {print} /^### 外部来源/ {in_tbl=1; next} in_tbl && /^\|[: -]+\|/ && inserted==0 {print row; inserted=1; next} in_tbl && /^### / && inserted==0 {print row; inserted=1; in_tbl=0} END{if(inserted==0) print row} ' "$WIKI" > "$WIKI.tmp" && mv "$WIKI.tmp" "$WIKI" ``` #### Content writer ```bash abs_path() { local p="$1" case "$p" in /*) printf '%s' "$p" ;; *) printf '%s/%s' "$VAULT" "$p" ;; esac } WIKI="$(abs_path "$WIKI_REL")" if [ ! -f "$WIKI" ]; then error "Wiki 不存在: $WIKI" exit 1 fi TMP_WIKI="$WIKI.tmp.$$" ``` The constructed path is ultimately replaced: ```bash mv "$TMP_WIKI" "$WIKI" ``` #### Status writer ```bash abs_path() { local p="$1" case "$p" in /*) printf '%s' "$p" ;; *) printf '%s/%s' "$VAULT" "$p" ;; esac } DOC="$(abs_path "$DOC_REL")" ``` The selected file is replaced after transformation: ```bash TMP_DOC="$DOC.tmp.$$" awk -v to_status="$TO_STATUS" ' NR==1 && $0=="---" { in_frontmatter=1; print; next } i ...[truncated 4338 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Canonicalize the vault once and canonicalize every target before reading or writing: ```python vault = Path(vault_value).resolve(strict=True) target = (vault / supplied_path).resolve(strict=True) try: target.relative_to(vault) except ValueError: fail("Path escapes the configured vault") ``` 2. Reject absolute paths for arguments documented as vault-relative. 3. Constrain each file to its intended subdirectory: - Wiki targets must remain under the domain directory. - Source documents must remain under the transit directory. - Graduated destinations must remain under the graduated directory. - Index operations must target the configured index file only. 4. Reject path components equal to `..` before resolution as an additional early validation measure. 5. Verify containment after symlink resolution. Where symlinks are unnecessary, reject them with `lstat` or `Path.is_symlink()`. 6. Open or replace files using directory-file-descriptor-based APIs where available to reduce time-of-check/time-of-use races. 7. Do not allow arbitrary environment variables to redirect sensitive write destinations unless they are validated against the same policy. 8. Validate destination type, ownership, and permissions before replacement. 9. Apply consistent path validation in every read-only and mutating script, not only in the precheck. 10. Add automated tests for absolute paths, `../` traversal, nested traversal, symlink escapes, and destination-directory overrides. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/wiki_entry_xref_sync.sh:54
Finding
Content-Controlled Wikilinks Enable Cross-Reference Writes Outside the Domain Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wiki_entry_xref_sync.sh:54-100` **Vulnerability Type**: Path traversal from untrusted document content **Risk Level**: High ### Vulnerable Code The script extracts arbitrary wikilink contents from the current document: ```bash extract_related_links() { local file="$1" local in_section=0 while IFS= read -r line; do if echo "$line" | grep -q '^## 相关主题'; then in_section=1 continue fi if [ "$in_section" -eq 1 ] && echo "$line" | grep -q '^## '; then break fi if [ "$in_section" -eq 1 ]; then echo "$line" | grep -oE '\[\[[^]]+\]\]' | sed 's/\[\[//;s/\]\]//' fi done < "$file" } ``` The extracted value is directly converted into a filesystem path: ```bash while IFS= read -r target_name; do [ -z "$target_name" ] && continue TARGET_FILE="$WIKI_DIR/${target_name}.md" if [ ! -f "$TARGET_FILE" ]; then echo "⚠️ 目标不存在: [[${target_name}]](文件 $TARGET_FILE 未找到)" continue fi ``` If the target exists, the script writes to it: ```bash if grep -q "\[\[$WIKI_BASENAME\]\]" "$TARGET_FILE"; then echo "✅ [[${target_name}]] ↔ [[$WIKI_BASENAME]] 已对称" else if grep -q '^## 相关主题' "$TARGET_FILE"; then awk -v link="- [[$WIKI_BASENAME]] — 交叉引用(自动补链)" ' /^## 相关主题/ { in_sec=1; print; next } in_sec && /^## / { print link; print ""; in_sec=0 } { print } END { if (in_sec) print link } ' "$TARGET_FILE" > "${TARGET_FILE}.tmp" && mv "${TARGET_FILE}.tmp" "$TARGET_FILE" else printf '\n## 相关主题\n- [[%s]] — 交叉引用(自动补链)\n' \ "$WIKI_BASENAME" >> "$TARGET_FILE" fi HAD_FIX=1 fi done <<< "$LINKS" ``` ### Technical Analysis The value between `[[` and `]]` is treated as both a logical wiki name and a filesystem path. The extraction expression accepts slash characters, parent-directory components, and other path syntax. For example: ```markdown ## Related Topics - [[../../outside/t ...[truncated 2083 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define and enforce a strict wiki-target grammar. If only shortest wikilinks are required, permit a conservative set of page-name characters and reject: - `/` and `\` - `..` - Absolute path prefixes - NUL and control characters - Newlines 2. Resolve the target canonically and verify that it remains under the canonical domain directory: ```python domain = Path(domain_value).resolve(strict=True) target = (domain / f"{target_name}.md").resolve(strict=True) target.relative_to(domain) ``` 3. Reject symlink targets or verify that the fully resolved target remains inside the domain directory. 4. Separate wiki-link parsing from filesystem resolution. Do not assume all valid wiki syntax is safe path syntax. 5. Prefer resolving page names through an indexed mapping of known domain pages rather than constructing paths directly. 6. Use secure atomic replacement after validation and preserve file permissions. 7. Add regression tests using `../`, nested traversal, absolute-like names, encoded separators, and symlink escapes. 8. Treat all note content as untrusted, even when it was generated earlier in the same Agent workflow. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_shared/query_history.sh:187
Finding
Predictable Temporary Files Permit Symlink-Based File Clobbering<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_shared/query_history.sh:187-203` **Vulnerability Type**: Insecure predictable temporary files and symlink race **Risk Level**: Medium ### Vulnerable Code ```bash TMP_BASE="$TMPDIR/query-history-$$" RECENT_FILE="$TMP_BASE.recent" EVO_FILE="$TMP_BASE.evo" CONTRA_FILE="$TMP_BASE.contra" RECENT_SEEN="$TMP_BASE.recent.seen" EVO_SEEN="$TMP_BASE.evo.seen" : > "$RECENT_FILE" : > "$EVO_FILE" : > "$CONTRA_FILE" : > "$RECENT_SEEN" : > "$EVO_SEEN" cleanup() { rm -f "$RECENT_FILE" "$EVO_FILE" "$CONTRA_FILE" \ "$RECENT_SEEN" "$EVO_SEEN" } trap cleanup EXIT ``` ### Technical Analysis Temporary filenames are derived from the shared temporary directory and the process ID. Process IDs are observable or predictable, and the files are not created with exclusive-open semantics. The truncation operation: ```bash : > "$RECENT_FILE" ``` follows symbolic links. A local attacker with access to the same writable temporary directory can pre-create one of the expected names as a symbolic link to another file writable by the Agent account. When the script initializes the temporary file, it truncates the symlink target. The subsequent append operations may also write query results through the symlink. Cleanup removes the symlink name rather than restoring the target file. The code also directly references `$TMPDIR` without the guarded default used elsewhere. If `TMPDIR` is unset under the script's current `set -u` behavior, execution can fail; if it is attacker-controlled, it can redirect temporary storage to an untrusted location. ### Attack Path 1. A local attacker observes or predicts a process ID likely to be assigned to the history-query script. 2. The attacker creates a symbolic link in the shared temporary directory: ```text query-history-PID.recent -> writable_target ``` 3. The script starts with the predicted PID. 4. The initialization redirection follows the symbolic link and truncates `writ ...[truncated 858 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a private temporary directory with `mktemp -d`: ```bash TMP_WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/query-history.XXXXXX")" || exit 1 chmod 700 "$TMP_WORK_DIR" ``` 2. Place all temporary files inside that directory: ```bash RECENT_FILE="$TMP_WORK_DIR/recent" EVO_FILE="$TMP_WORK_DIR/evo" ``` 3. Clean up only the private directory: ```bash trap 'rm -rf -- "$TMP_WORK_DIR"' EXIT HUP INT TERM ``` 4. Use `${TMPDIR:-/tmp}` rather than directly referencing an optionally unset variable. 5. Do not use PID-based names as a uniqueness or security mechanism. 6. Where individual files must be created independently, use exclusive creation through `mktemp` or an API using `O_CREAT | O_EXCL`. 7. Verify temporary-directory ownership and permissions if a caller may configure `TMPDIR`. 8. Add a regression test that pre-creates symlinks matching legacy temporary names and confirms that external targets remain unchanged. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (37)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Unlike the other mismatch reports, this one mentions execution of arbitrary shell via an `--audit-cmd` parameter. If the associated checkpoint/audit helper actually accepts and executes caller-provided shell, that would create a command-injection path inside a skill already authorized to touch repository content and state files, making the workflow materially more dangerous.

Ae1

High
Category
analysis-evasion
Content
4. 所有步骤都要走 `wiki_entry_step_checkpoint.sh` 记录状态。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
4. 所有步骤都要走 `wiki_entry_step_checkpoint.sh` 记录状态。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The script directly executes the user-supplied --audit-cmd with `bash -lc`, giving the caller arbitrary shell execution in the context of the agent/runtime. That is far broader than a checkpoint/status helper needs, and in this skill context it can be abused to run destructive commands, exfiltrate vault data, or modify unrelated files under the guise of an audit step.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill is explicitly designed to read environment variables and modify files, but it does not declare any tool/permission scope to bound those capabilities. In practice this weakens policy enforcement and reviewability: an operator or runtime cannot easily tell that the skill can read configuration and write wiki, index, state, and status files before invocation.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The instruction at L010 is written as a direct role definition in Chinese and sets the skill's operating behavior in a specific language, with no indication that the user may choose another language. Under the locale-policy rule, forcing a specific language without opt-in is a natural-language policy violation.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill is user-invocable and explicitly says the executor should continue after Step 3 without waiting for confirmation, while also modifying wiki content, metadata, indexes, and note status. Without a clear user-facing warning and confirmation model, an operator may trigger destructive or hard-to-reverse repository changes unexpectedly, especially because the workflow spans multiple files and status transitions.

Natural-Language Policy Violations

Medium
Confidence
83% confidence
Finding
The file title and all operational guidance are written entirely in Chinese, and there is no indication that language choice is optional or that the skill is intentionally region-specific. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
78% confidence
Finding
All user-facing instructions in this file are presented exclusively in Chinese, with no indication that language selection is optional or that the skill is intentionally limited to a Chinese-speaking context. This can conflict with language/locale policy requirements that prohibit forcing a specific language without user opt-in.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file’s headings and checklist items are entirely written in Chinese, including operational instructions such as status checks and reporting steps. Under the policy, forcing a specific language without user opt-in or a documented justification is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The natural-language interface exposed by the script is entirely in Chinese in its usage output, and additional user-facing error/status messages throughout the file follow the same pattern. This imposes a specific language on users without any opt-in, fallback, or justification for a locale-specific scope.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The usage text is presented only in Chinese, and the rest of the script likewise emits Chinese status and error messages. For a shared shell utility, this is a natural-language locale policy issue because users are not given any language/locale opt-in and no region-specific justification is documented in the file.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
This shell script rewrites the target wiki file in place using `mv "$TMP_WIKI" "$WIKI"`, which can replace existing content and is potentially destructive, especially in `replace` mode. While the script prints a success message afterward, there is no prior confirmation prompt or explicit warning comment/docstring near the write operation itself disclosing that the file will be modified.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This shell script presents its argument error and usage text entirely in Chinese, and the rest of the script continues with Chinese status and failure messages. That imposes a specific language on users without any opt-in or justification, which matches the language/locale policy violation category.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This shell script replaces the target document by moving a temporary file over the original, which is a file write operation affecting user data. Although the script prints a success message afterward, there is no pre-action warning, confirmation prompt, or explanatory comment/docstring disclosing that the original file will be modified in place.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Because --audit-cmd is executed immediately and there is no confirmation, warning, or policy gate, any caller that can influence this argument can trigger arbitrary shell commands without meaningful user awareness. In an agent skill, this increases the risk of prompt-driven or workflow-driven command execution, especially since the feature is framed as a routine micro-audit rather than a dangerous operation.

Static analysis

No suspicious patterns detected.