Back to skill

Security audit

公众号标题生成与评分

Security checks for vulnerabilities and agentic risk

Overview

The skill’s main purpose is coherent, but it needs review because it uses a RedFox API key, makes external requests, and writes local files with weak safeguards.

Install only if you are comfortable giving this skill a RedFox API key and sending your title keywords to redfox.hk. Avoid using --debug until the key logging is fixed, prefer a scoped/revocable API key, and run it from a directory where generated Markdown files cannot overwrite anything important.

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/fetch_official_account_trends.py:58
Finding

API Key Disclosed in Debug Logs

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch_official_account_trends.py, lines 58-77
Vulnerability Type: Sensitive credential exposure through diagnostic output
Risk Level: Medium

Vulnerable Code:

python
# 从环境变量获取API Key
api_key = os.environ.get("REDFOX_API_KEY")
if not api_key:
    raise Exception("缺少 REDFOX_API_KEY 环境变量,请先配置 API Key。获取地址:https://redfox.hk/settings/api-keys?source=clawhub")

# 请求头
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "X-API-Key": api_key
}

last_error = None
for attempt in range(max_retries):
    try:
        if debug:
            print(f"\n=== DEBUG: 第 {attempt + 1} 次尝试 ===", file=sys.stderr)
            print(f"URL: {url}", file=sys.stderr)
            print(f"Params: {params}", file=sys.stderr)
            print(f"Headers: {headers}", file=sys.stderr)

Technical Analysis

The API credential is retrieved appropriately from the REDFOX_API_KEY environment variable, but it is then placed into the headers dictionary. When the user supplies the --debug option, the entire dictionary is written to standard error without redaction. Consequently, the plaintext value of the X-API-Key header is exposed.

Standard error is frequently captured by CI systems, agent execution transcripts, shell logging, centralized observability platforms, and support bundles. The exposure therefore persists beyond the immediate process and contradicts the project documentation's instruction not to expose keys in logs.

Attack Path

  1. A user configures a valid REDFOX_API_KEY in the process environment.
  2. An attacker, malicious instruction, or troubleshooting procedure persuades the user or agent to invoke the script with --debug.
  3. The script constructs ...[truncated 870 chars]
Remediation
View remediation

Remediation Suggestions

  • Never print the original authentication-header dictionary.

  • Construct a sanitized copy before diagnostic output:

    python
    if debug:
        safe_headers = {
            key: ("***REDACTED***" if key.lower() in {"x-api-key", "authorization"} else value)
            for key, value in headers.items()
        }
        print(f"Headers: {safe_headers}", file=sys.stderr)
    
  • Prefer an allowlist for logged metadata rather than redacting a full structure. For example, log only the URL, attempt number, timeout, and non-sensitive parameter names.

  • Add automated tests that run debug mode with a sentinel credential and assert that the sentinel never appears in either standard output or standard error.

  • Review historical logs for exposed keys and rotate any credential that may already have been recorded.

  • Apply server-side restrictions such as minimum required scopes, quotas, expiration, and straightforward revocation.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_official_account_trends.py:347
Finding

User-Controlled Keyword Used as an Unrestricted Output Path

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch_official_account_trends.py, lines 347-349 and 379-380
Vulnerability Type: Path traversal and unintended file overwrite
Risk Level: Medium

Vulnerable Code:

python
# 如果指定了输出文件,保存到文件
if output_file:
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(content)
python
# 生成输出
output_file = args.output if args.output else f"{args.keyword}_爆款数据.md"
content = generate_markdown_output(args.keyword, data, output_file)

Technical Analysis

The command-line keyword originates from user-controlled content. When --output is not supplied, that value is directly incorporated into the output path without removing directory separators, resolving traversal components, restricting the destination to a designated results directory, or checking whether the destination already exists.

Because open(..., 'w') truncates an existing file, a keyword containing an absolute path or ../ components can cause the script to create or overwrite a suffixed Markdown file outside its intended working directory. The fixed _爆款数据.md suffix limits the exact filenames that can be targeted, but it does not prevent directory traversal or writes to unintended locations.

The explicit --output argument is also unrestricted. That may be acceptable for a trusted command-line utility, but it becomes dangerous when arguments are generated automatically by an agent from untrusted user input.

Attack Path

  1. An attacker supplies a crafted keyword containing an absolute path or traversal components, such as a path under another writable project directory.
  2. An agent passes the value to --keyword as directed by the Skill workflow and does not supply a safe --output path.
  3. The script successfully queries the remote API.
  4. The default filename is formed from the malicious keyword plus _爆款数据.md.
  5. generate_markdown_output calls `op ...[truncated 1001 chars]
Remediation
View remediation

Remediation Suggestions

  • Write generated files only beneath a fixed, dedicated output directory.

  • Convert the keyword to a safe filename component by removing path separators and allowing only a conservative character set, or use a hash as the filename.

  • Resolve the final path and verify that it remains beneath the intended directory:

    python
    from pathlib import Path
    import hashlib
    
    output_root = Path("output").resolve()
    output_root.mkdir(parents=True, exist_ok=True)
    
    keyword_id = hashlib.sha256(args.keyword.encode("utf-8")).hexdigest()[:16]
    output_file = (output_root / f"{keyword_id}_trends.md").resolve()
    
    if output_root not in output_file.parents:
        raise ValueError("Invalid output path")
    
  • If human-readable names are required, normalize the keyword to a strict slug and reject /, \, .., control characters, and absolute paths.

  • Avoid silent truncation. Use exclusive creation mode ('x') when replacement is unnecessary, or require explicit confirmation before overwriting an existing file.

  • If --output remains supported, treat it as a trusted-administrator option or apply the same destination-directory validation.

  • Add tests covering absolute paths, nested traversal, platform-specific separators, control characters, and attempts to overwrite existing files.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (14)

Tainted flow: 'headers' from os.environ.get (line 63, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fetch_official_account_trends.py (reported line 80)May include surrounding context.

python
print(f"Headers: {headers}", file=sys.stderr)

            # 发送请求
            response = requests.get(url, params=params, headers=headers, timeout=60)

            if debug:
                print(f"状态码: {response.status_code}", file=sys.stderr)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill is presented primarily as a title-generation/scoring tool, but the implemented behavior depends on external API retrieval, local file generation/reading, and operational steps not transparently reflected in the declared behavior. This mismatch can mislead routing, user consent, and security review, causing the skill to be invoked in contexts where networked data access and file handling were not expected.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The description and trigger phrases are broad enough to match many adjacent content-creation requests, increasing the chance of unintended activation. Unnecessarily broad invocation can expose API-backed retrieval and file/network capabilities in conversations that did not clearly request this skill, which expands attack surface and weakens user intent validation.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The instruction to treat any user input as a request for title generation or scoring removes meaningful trigger boundaries and effectively authorizes the skill to reinterpret unrelated prompts. In a skill with network, env, and file capabilities, this is dangerous because it can cause unintended external queries, data handling, and misleading responses without clear user consent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README instructs users to invoke the skill with very broad, natural-language requests such as generic title-generation or trend queries. In agent environments that auto-route based on prompt similarity, this can cause unintended activation on ordinary user requests, leading to unnecessary external data access, confusion, or disclosure of user content to the third-party service behind the skill. The risk is elevated because the examples are common editorial requests rather than narrowly scoped command phrases.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README says users can 'directly use natural language to describe your needs' without fixed commands, but it does not define boundaries, required keywords, or exclusion conditions. For a markdown skill description, this creates an ambiguous trigger surface that could overlap with ordinary requests and lead to unintended invocation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The example '最近公众号什么标题火,帮我编几条' is framed as a valid invocation, but it is a broad everyday-style request rather than a narrowly scoped command. The README does not clarify when such generic wording should or should not activate the skill.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill requires environment access for an API key, network access to a third-party endpoint, and file output/reading behavior, yet it declares no explicit tool scope or permissions. This creates a least-privilege failure: a host may expose broader capabilities than intended, and reviewers/users cannot accurately assess what the skill will access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

In debug mode, the script prints the full request headers to stderr, including the X-API-Key value. This can leak credentials into terminal scrollback, CI logs, agent traces, or centralized logging systems, enabling unauthorized use of the API key by anyone with log access. In this skill context, the danger is increased because the skill is designed to call an external service using a secret, and debugging may be enabled during troubleshooting or automated runs.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes a professional tool for generating公众号爆款标题 or scoring user-provided titles, with trend lookup only as one of several use cases. In this file, the implemented behavior is limited to querying external trend data and formatting/saving article rankings as Markdown, with no title generation or scoring logic present.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
71% confidence
Finding

The natural-language description is centered on WeChat Official Account content and WeChat viral article data, which implies a specific locale/platform context. While this may be reasonable for the domain, the file does not explicitly offer language or locale choice or document the constraint as a region-specific limitation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The function docstring states the return value contains '3类爆款数据', creating a concrete expectation about output structure. The implementation only returns 'oneWReadingRank' and 'originalRank', so the inline documentation actively misstates what the function actually provides.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The manifest frames the skill as a content ideation/title tool, not as a credential-dependent integration. While network access for trend lookup is plausible, implicit dependency on a secret from process environment is an additional operational capability not disclosed by the stated purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code forces the request locale to zh-CN,zh;q=0.9 for all users. This is a natural-language/locale policy concern because it imposes a specific language preference without offering opt-in or documenting why the restriction is required.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.