Back to skill

Security audit

wacai-index-official-website-demand-dev

Security checks for vulnerabilities and agentic risk

Overview

The skill's website-change workflow is mostly coherent, but it can push repository changes and automatically send repository metadata or arbitrary summary-file contents to a hardcoded WeCom webhook.

Review carefully before installing. Only run it in repositories where automatic commit and push are acceptable, remove or replace the hardcoded WeCom webhook, avoid passing untrusted summary files or demand filenames, and add path validation and a confirmation step before push and notification.

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/push_wecom_push_notice.py:13
Finding
Hardcoded WeCom webhook transmits repository metadata to a preconfigured external recipient<![CDATA[ ## Vulnerability Details **File Location**: `scripts/push_wecom_push_notice.py:13`, `scripts/push_wecom_push_notice.py:113-124`, `scripts/push_wecom_push_notice.py:147-163`, `scripts/run_git_flow.sh:30-34` **Vulnerability Type**: Hardcoded webhook credential and unauthorized external data transmission **Risk Level**: Critical ### Vulnerable Code ```python DEFAULT_WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=0e41994e-9e62-4713-ad69-fddeaaba8e9a" ``` ```python def build_content(project_dir: Path, branch: str, commit_ref: str, summary: str) -> str: commit_hash = run_git(project_dir, "rev-parse", "--short", commit_ref) commit_subject = run_git(project_dir, "show", "-s", "--format=%s", commit_ref) timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") summary = summary.strip() if summary.strip() else summarize_from_diff(project_dir, commit_ref) return "\n".join([ f"时间:{timestamp}", f"项目:{project_dir}", f"分支:{branch}", f"提交:{commit_hash} {commit_subject}", "代码变动点:", summary, ]) ``` ```python parser.add_argument( "--webhook-url", default=os.environ.get("WECOM_WEBHOOK_URL", DEFAULT_WEBHOOK_URL), help="Override webhook URL" ) response_text = post_json(args.webhook_url, payload) ``` ```bash NOTICE_ARGS=(--project-dir "$PROJECT_DIR" --branch "$BRANCH" --commit-ref HEAD) if [[ -n "$SUMMARY_FILE" ]]; then NOTICE_ARGS+=(--summary-file "$SUMMARY_FILE") fi python3 "$SCRIPT_DIR/push_wecom_push_notice.py" "${NOTICE_ARGS[@]}" ``` ### Technical Analysis The notification script contains a complete WeCom webhook URL, including its secret webhook key. If `WECOM_WEBHOOK_URL` is not configured and the caller does not provide `--webhook-url`, the embedded endpoint is used automatically. After a successful Git push, `run_git_flow.sh` invokes the notification script without specifying a webhook URL. The script consequently sends the following information to the ...[truncated 1756 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `DEFAULT_WEBHOOK_URL` and the embedded key from the source code. 2. Rotate or revoke the exposed webhook key immediately. 3. Require `WECOM_WEBHOOK_URL` or `--webhook-url` to be explicitly configured, and fail closed when neither is present. 4. Validate that the destination uses HTTPS and, where operationally possible, restrict the hostname to an approved allowlist. 5. Clearly disclose every field sent to the webhook and obtain confirmation before the first transmission. 6. Replace the absolute project path with a configured project name or repository basename. 7. Minimize the payload by omitting commit details and filenames unless the user explicitly enables them. 8. Store webhook credentials in a secret manager or protected environment variable rather than source control. 9. Avoid printing credential-bearing webhook URLs in logs or error messages. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/push_wecom_push_notice.py:47
Finding
Arbitrary local files can be read and transmitted through the summary-file option<![CDATA[ ## Vulnerability Details **File Location**: `scripts/push_wecom_push_notice.py:47-54`, `scripts/push_wecom_push_notice.py:145-163` **Vulnerability Type**: Unrestricted local-file read leading to data exfiltration **Risk Level**: High ### Vulnerable Code ```python def read_summary(args) -> str: if args.summary: return args.summary.strip() if args.summary_file: return Path(args.summary_file).read_text(encoding="utf-8").strip() if args.stdin: return sys.stdin.read().strip() return "" ``` ```python parser.add_argument("--summary-file", help="Path to summary text file") parser.add_argument( "--webhook-url", default=os.environ.get("WECOM_WEBHOOK_URL", DEFAULT_WEBHOOK_URL), help="Override webhook URL" ) ``` ```python summary = read_summary(args) content = build_content(project_dir, args.branch, args.commit_ref, summary) payload = { "msgtype": "text", "text": { "content": content } } response_text = post_json(args.webhook_url, payload) ``` ### Technical Analysis The `--summary-file` argument accepts an unrestricted filesystem path. The script resolves no project boundary, performs no sensitive-path checks, does not reject symbolic links, and applies no file-size limit. It reads the complete UTF-8 contents and inserts them into the outbound webhook message. The shell wrapper forwards its third positional argument directly as `--summary-file`. Therefore, any caller able to influence this argument can make the script read any UTF-8 file accessible to the current operating-system user. The read operation uses the existing process privileges; it does not bypass operating-system permissions. Nevertheless, it exceeds the minimum access needed for a repository change summary because the file does not have to reside in the target project. ### Attack Path 1. An attacker or untrusted automation gains control over the `summary-file` argument. 2. The argument is set to a sensitive readable f ...[truncated 1169 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve both the project directory and summary path to canonical paths. 2. Require the summary file to remain beneath an approved project subdirectory. 3. Reject absolute paths, traversal components, and paths that resolve outside the approved root. 4. Reject symbolic links or verify the final resolved target before opening it. 5. Permit only an expected filename or a generated temporary summary owned by the workflow. 6. Apply a strict size limit before reading, such as a few kilobytes. 7. Reject known-sensitive names and locations, including `.env`, credential files, private keys, and hidden configuration directories. 8. Prefer passing a generated summary through standard input rather than accepting an arbitrary path. 9. Display the final redacted notification and destination for user confirmation before transmission when sensitive repositories are involved. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run_git_flow.sh:20
Finding
Git option injection can stage and push files outside the requested file list<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_git_flow.sh:7-8`, `scripts/run_git_flow.sh:20-27` **Vulnerability Type**: Git argument and option injection **Risk Level**: High ### Vulnerable Code ```bash SUMMARY_FILE="${3:-}" shift 3 || true ``` ```bash git add "$@" STAMP="$(date '+%Y%m%d-%H%M%S')" MSG="chore: 官网需求变更-${STAMP}" git commit -m "$MSG" git push origin "$BRANCH" ``` ### Technical Analysis Although the file arguments are shell-quoted, they are passed to `git add` without the standard `--` option terminator. Shell quoting prevents shell metacharacter expansion but does not prevent the called program from interpreting an argument beginning with `-` as an option. For example, a supplied file argument of `--all` or `-A` instructs Git to stage changes across the working tree rather than stage only an intended path. The script then commits and pushes the resulting index automatically. This is an application-level argument injection vulnerability rather than shell command injection. It can cause unintended repository content to be committed even though it does not directly execute arbitrary shell commands. ### Attack Path 1. A caller or upstream agent supplies the required positional arguments to `run_git_flow.sh`. 2. One of the purported file arguments is an option such as `--all`. 3. The script executes: ```bash git add --all ``` 4. Git stages unrelated modified, deleted, or untracked files from the repository. 5. The script creates a commit without reviewing the staged paths. 6. The commit is pushed to the specified remote branch. 7. Any staged secrets or unrelated work become available to users with access to the remote repository. ### Impact Assessment An attacker who can influence the file argument list can expand the scope of the commit from selected files to the entire repository working tree. Potential consequences include: - Committing `.env` files, tokens, keys, or local configuration - Publishing unrelated or un ...[truncated 351 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Terminate Git option parsing explicitly: ```bash git add -- "$@" ``` 2. Reject file arguments beginning with `-`, even when using the option terminator, to make misuse visible. 3. Canonicalize and validate each requested path against the repository root. 4. Reject paths outside the repository and unexpected symbolic links. 5. Before committing, inspect the staged file list: ```bash git diff --cached --name-only ``` 6. Compare staged paths against the approved input list and abort if extra files are present. 7. Add explicit checks for common secret files and private-key formats. 8. Consider requiring user confirmation when the staged set contains untracked files, deletions, or files not named in the request. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/update_productdemand.sh:17
Finding
Demand filename traversal permits arbitrary writable-file overwrite outside the project<![CDATA[ ## Vulnerability Details **File Location**: `scripts/update_productdemand.sh:5`, `scripts/update_productdemand.sh:17-30` **Vulnerability Type**: Path traversal and arbitrary file overwrite **Risk Level**: High ### Vulnerable Code ```bash DEMAND_FILE_NAME="${3:-productdemand.md}" ``` ```bash TARGET_FILE="$PROJECT_DIR/$DEMAND_FILE_NAME" TIMESTAMP_HOUR="$(date '+%Y-%m-%d-%H')" BACKUP_FILE="$PROJECT_DIR/productdemand.backup.${TIMESTAMP_HOUR}.md" mkdir -p "$PROJECT_DIR" if [[ -f "$TARGET_FILE" ]]; then cp "$TARGET_FILE" "$BACKUP_FILE" echo "BACKUP_FILE=$BACKUP_FILE" else echo "BACKUP_FILE=" fi cp "$INPUT_FILE" "$TARGET_FILE" ``` ### Technical Analysis The optional demand filename is concatenated directly with the project directory. The script does not require it to be a basename and does not canonicalize the resulting target or verify that it remains within the project root. A value containing parent-directory components, such as `../../target-file`, can escape the project directory. If the resulting target exists, the script first copies its previous contents into the project backup and then overwrites the target with the attacker-selected input file. The script also does not reject symbolic-link targets. Consequently, a path that appears to be inside the project may resolve to a writable file outside it. ### Attack Path 1. An attacker or untrusted caller controls the third argument, `demand-file-name`. 2. The attacker supplies a traversal value such as: ```text ../../path/to/writable-target ``` 3. `TARGET_FILE` is constructed using the unvalidated value. 4. Filesystem path resolution escapes the intended project directory. 5. If the external target exists, its content is copied to the predictable backup file inside the project. 6. The input Markdown file is copied over the external target. 7. If the backup is later staged and pushed, the original external file contents may also be exposed through the repository. A symbolic link inside ...[truncated 952 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict `DEMAND_FILE_NAME` to an approved basename, preferably exactly `productdemand.md`. 2. Reject values containing `/`, backslashes, `..`, control characters, or leading option characters. 3. Canonicalize `PROJECT_DIR` and the parent directory of the intended target. 4. Verify that the resolved target remains beneath the canonical project root before copying. 5. Reject symbolic links for both the target and relevant parent components. 6. Avoid `mkdir -p` on an unvalidated project path; require an existing, validated Git repository. 7. Create backups with restrictive permissions and collision-resistant names. 8. Do not automatically stage backup files unless their contents have been reviewed. 9. Use a temporary file inside the verified project directory and perform an atomic rename only after all checks pass. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The description presents an end-to-end requirement-to-code modification workflow, including documentation sync, backup, code changes, validation, Git commit/push, and WeCom notification. The actual code chunk is much narrower: it is a Git automation helper that stages provided files, commits, pushes, and triggers a notice script. While branch update, commit/push, and notification broadly align with part of the description, several core declared behaviors are absent from this code: no requirement ingestion, no writing to productdemand.md, no backup, no code modification, and no validation. This is a material description-versus-behavior mismatch because the declared primary purpose is broader and more capable than what the supplied code actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The actual code implements only a narrow subset of the declared behavior: creating the project directory, backing up an existing demand markdown file, and replacing it with the supplied input file. The declared description presents a much broader automation workflow involving repository operations, source code changes, validation, and external notification. Those core capabilities are absent from the supplied code chunk, so the description does not accurately represent what this code actually does.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises and recommends shell, git, file, environment, and network-driven actions but does not declare any explicit tool scope or allowed-tools boundary. In a skill that can modify arbitrary project paths, push code, and send webhooks, missing scope constraints increases the chance of overbroad execution and makes dangerous capabilities insufficiently governed.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill requires sending project path, branch, commit metadata, and code-change summaries to an external WeCom webhook without any warning, consent gate, minimization guidance, or destination validation. That can leak sensitive repository structure, internal filenames, branch names, and development activity to a third-party endpoint, especially dangerous because the skill operates on externally supplied project paths and potentially private codebases.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_git(project_dir: Path, *args: str) -> str:
    result = subprocess.run(
        ["git", *args],
        cwd=str(project_dir),
        check=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The script automatically sends project path, branch, commit hash/subject, changed-file-derived summary, and potentially diff-derived details to an external WeCom webhook. It also embeds a default webhook token directly in code, which can enable unintended outbound data disclosure and unauthorized notifications without explicit runtime consent or visibility to the operator.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This code fetches, checks out, pulls, stages files, commits, and pushes to a remote branch, which changes repository state and transmits data to a remote system. While the script name suggests a git workflow, there is no confirmation prompt, cautionary comment, or user-facing warning in the file before these potentially impactful operations occur.

Missing User Warnings

Medium
Confidence
81% confidence
Finding
The script invokes another program to send a notice using project directory, branch, commit reference, and optionally a summary file, which may transmit user or system data over a network. There is no warning, comment, or user-facing disclosure here explaining that metadata will be sent after the git operations complete.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The script constructs commit messages with a fixed Chinese phrase, forcing a specific language regardless of user preference or repository conventions. This is a natural-language locale constraint with no opt-in, configurability, or justification present in the file.

Static analysis

No suspicious patterns detected.