Back to skill

Security audit

公众号订阅追踪

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly does the advertised WeChat article tracking, but it needs review because its scheduled automation and HTML reports handle credentials and untrusted data unsafely.

Review this skill before installing. Avoid enabling the daily scheduled task until cron/LaunchAgent handling is fixed, avoid passing the API key on the command line or storing it in plaintext, and treat generated reports as untrusted HTML because article metadata is inserted without escaping.

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

T09 · Insecure Skill Coding Practices

Error
Location
assets/subscribe.py:690
Finding

Shell Command Injection in Cron Task Management

Content
View full analysis
/dev/null; echo "{cron_line}") | crontab -', shell=True, check=True, capture_output=True ) ``` The related task-removal code at lines 721–726 is also unsafe: ```python script_path = os.path.abspath(__file__) try: subprocess.run( f'crontab -l 2>/dev/null | grep -v "{script_path}" | crontab -', shell=True, check=True, capture_output=True ) ``` ### Technical Analysis The absolute path of the Skill script is interpolated directly into shell commands executed with `shell=True`. No shell quoting or escaping is applied. Although `script_path` is not supplied as a normal command-line argument, it depends on the directory into which the Skill package is installed or extracted. If that directory contains shell metacharacters, command substitution syntax, quotes, or newline characters, the shell can interpret part of the path as executable syntax. The removal operation introduces an additional integrity problem: the path is passed to `grep` as an unescaped regular expression. Regex metacharacters in the path can cause unrelated cron entries to be removed. The scheduled task itself supports the documented daily-fetch feature and is installed only when the user requests `--subscribe`. Therefore, the persistence behavior is not independently classified as malicious system persistence. The vulnerability is the unsafe shell construction used to implement it. ### Attack Path 1. An attacker distributes or arranges extraction of the Skill under a directory name containing shell syntax. 2. The victim or an AI Agent invokes: ```b ...[truncated 1246 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
assets/subscribe.py:475
Finding

Stored HTML Injection in Automatically Opened Reports

Content
View full analysis
{pub_date} {author} {title} {summary} {reads} {likes} """ ``` The generated file is automatically opened at lines 893–897: ```python if sys.platform == "darwin": subprocess.run(["open", str(output_path)], check=False) elif sys.platform == "linux": subprocess.run(["xdg-open", str(output_path)], check=False) ``` ### Technical Analysis Article metadata is inserted directly into HTML text nodes and attributes without contextual escaping. Relevant values include: - Account or author name. - Article title. - Article summary. - Publication date. - Article URL. Most fields or ...[truncated 2006 chars]
Remediation
View remediation
``` - Avoid automatically opening reports containing remote or untrusted content, or require explicit user confirmation. - Add tests with payloads targeting element text, quoted attributes, URLs, and event handlers. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
assets/subscribe.py:639
Finding

API Key Persisted in Plaintext macOS LaunchAgent Configuration

Content
View full analysis
EnvironmentVariables {ENV_KEY} {api_key} """ ``` The value is incorporated into the LaunchAgent document and written at line 674: ```python plist_path.write_text(plist_content, encoding="utf-8") ``` ### Technical Analysis When scheduling is enabled on macOS, the Skill reads `REDFOX_API_KEY` from the process environment and copies it into a persistent plist under: ```text ~/Library/LaunchAgents/com.qoder.gzh-subscribe.plist ``` The API key is therefore converted from an environment-only secret into a long-lived plaintext file. This conflicts with the documentation in `README.en.md` and `README.md`, which instructs users not to expose API keys in plaintext files. The generated XML also does not escape the key before inserting it into a `` element. A key containing XML-special characters could corrupt the plist or alter its structure, although ordinary provider-issued keys may use a restricted character set. ### Attack Path 1. The user exports `REDFOX_API_KEY`. 2. The user or Agent enables daily scheduling with `--subscribe`. 3. The Skill reads the environment variable. 4. The key is embedded verbatim in the LaunchAgent plist. 5. The plist remains on disk across sessions and may be included in backups, support bundles, or user-directory copies. 6. Any process or person able to read the file can recover the API key. 7. The recovered key can be used against the RedFox API until it expires or is revoked. ### Impact Assessment An attacker obtaining the key may: - Consume the victim's API quota. - Access API capabilities granted to that key. - Impersonate the vi ...[truncated 272 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:18
Finding

Insecure API-Key Configuration Guidance

Content
View full analysis
~/.qoder/apis/redfox.json` | ``` The same guidance is repeated at lines 48–52. ### Technical Analysis Passing an API key using `--api-key` can expose the credential through: - Shell history. - Process listings. - Command auditing. - Terminal logs. - Automation logs and copied command transcripts. The configuration-file example writes the key in plaintext and does not explicitly set restrictive file permissions. The script's credential-loading implementation also does not verify that the file is owned by the current user or inaccessible to other users. Although environment variables are presented as the recommended option, they may also be inherited by child processes and exposed through debugging or process-inspection interfaces. The documentation should therefore explain the applicable trust boundary instead of presenting all three methods as equivalent. ### Attack Path 1. A user follows the documented `--api-key` example. 2. The complete command, including the secret, is recorded in shell history or automation logs. 3. Another local user, support operator, or process with access to those records retrieves the key. 4. Alternatively, the user creates the documented JSON file under permissive process defaults. 5. An unauthorized local process reads the plaintext file. 6. The attacker uses the credential against the RedFox API. ### Impact Assessment The exposed credential can be used within the API key's authorization scope. Likely effects include quota t ...[truncated 187 chars]
Remediation
View remediation

other

Note
Location
assets/report_template.html:9
Finding

Undisclosed Third-Party Requests from Generated Local Reports

Content
View full analysis
``` ### Technical Analysis The generated report is described as a local HTML report, but its template includes remote Google Fonts resources. When the report is opened, the browser contacts `fonts.googleapis.com` and `fonts.gstatic.com`. These requests are not necessary for subscription tracking, article retrieval, or report functionality. The project documentation does not disclose that opening a report contacts an additional third party. The requests may disclose network metadata such as the user's IP address, request time, browser headers, and user-agent characteristics. Depending on browser policy, referrer information may also be transmitted. ### Attack Path 1. The user runs `fetch` or `report`. 2. The Skill writes a local HTML report. 3. The Skill automatically opens the report in the default browser. 4. The browser processes the preconnect and stylesheet links. 5. Connections are made to Google-operated font services. 6. Those services receive the user's network and request metadata. No compromise of the RedFox API is required. ### Impact Assessment The primary impact is privacy leakage rather than code execution or privilege escalation. It creates an additional, undisclosed third-party data flow whenever a generated report is opened. The scope is limited to browser and network metadata ordinarily exposed by web requests; the code does not intentionally send the report contents or API key to the font provider. ]]>
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (43)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared purpose focuses on subscribing to public account articles, but the skill also instructs use of an external API with credentials, persistent local storage, scheduled task installation, and automatic browser opening. This mismatch is dangerous because it hides materially significant behaviors from users and policy systems, reducing informed consent and making it easier for a seemingly simple content skill to introduce persistence, data exposure, or external data transfer.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The shell command used to remove cron entries interpolates script_path directly into a grep expression and runs with shell=True. If the path contains quotes or shell metacharacters, an attacker controlling the install location could inject commands or corrupt the crontab, making this an actionable command-injection issue in a security-sensitive persistence path.

Content

Scanner excerpt · assets/subscribe.py (reported line 724)May include surrounding context.

python
else:
        script_path = os.path.abspath(__file__)
        try:
            subprocess.run(
                f'crontab -l 2>/dev/null | grep -v "{script_path}" | crontab -',
                shell=True, check=True, capture_output=True
            )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README promotes turning on an automatic 6 AM scheduled task but does not clearly warn that this makes a persistent system change that will continue running after the current session. In an agent environment, undisclosed persistence is risky because users may not realize the skill is installing recurring automation that consumes resources and performs future actions automatically.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README explicitly says users can invoke the skill with unrestricted natural language, which creates an overly broad trigger surface and makes it easier for unrelated prompts to activate subscription, fetching, scheduling, or browser-opening behaviors. In an agent setting, ambiguous activation increases the chance of unintended side effects such as persistent task creation or data retrieval without sufficiently explicit user consent.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · README.en.md (reported line 53)May include surrounding context.

md
### Common Phrases Cheat Sheet

| Intent                 | Example Phrase                                                                                          | Result                                                            |
| ---------------------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| Subscribe to an account | "Subscribe me to the RedFox Data Official Account, ID redfoxdata1, under Followed accounts"            | Added to your subscription list, ready for fetching anytime       |
| View subscriptions     | "Show me which Official Accounts I've subscribed to"                                                    | Lists all subscribed accounts by group                            |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README promotes a 'one-click' daily 06:00 scheduled task and browser auto-open behavior without clearly warning that this modifies the user's system configuration and causes recurring automated execution. Users may unknowingly authorize persistence-like behavior, resulting in unwanted scheduled jobs, repeated network access, and confusion about how to disable it.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README explains how to obtain and configure a third-party API key but does not clearly disclose that subscription targets, article-tracking queries, and related usage data will be transmitted to an external service. Because the skill is designed to monitor competitor and followed accounts, this can expose potentially sensitive business-interest data and operational patterns to the provider without informed consent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README tells users to invoke the skill with unrestricted natural language, which can cause the agent to trigger actions from ambiguous or incidental phrasing rather than an explicit, scoped command. In a skill that can create subscriptions, fetch external data, and enable scheduled tasks, broad invocation guidance increases the risk of unintended execution and surprise system/network activity.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises operational commands that use environment access, local file reads/writes, network calls, and shell execution, but it does not declare any tool scope or permissions boundary. This is dangerous because users and agent platforms cannot clearly understand or constrain what the skill is allowed to do, increasing the chance of over-privileged execution and unintended side effects such as persistence, credential access, or arbitrary command execution through the referenced script.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation explicitly recommends writing the API key to a plaintext file in the user's home directory without any warning about credential sensitivity or file permissions. This is dangerous because local users, malware, backups, or misconfigured permissions could expose the key, enabling unauthorized API use, quota theft, or account abuse.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This Python file contains user-facing natural-language content entirely in Chinese, including the top-level description and CLI usage, with no indication that language selection is optional. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 45)May include surrounding context.

python
MAX_SUBSCRIPTIONS = 20
DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderGzhReports"

PLIST_LABEL = "com.qoder.gzh-subscribe"
PLIST_DIR = Path.home() / "Library" / "LaunchAgents"

DEFAULT_CATEGORIES = ["竞对账号", "同类账号", "关注账号"]

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 46)May include surrounding context.

python
MAX_SUBSCRIPTIONS = 20
DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderGzhReports"

PLIST_LABEL = "com.qoder.gzh-subscribe"
PLIST_DIR = Path.home() / "Library" / "LaunchAgents"

DEFAULT_CATEGORIES = ["竞对账号", "同类账号", "关注账号"]

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 651)May include surrounding context.

python
MAX_SUBSCRIPTIONS = 20
DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderGzhReports"

PLIST_LABEL = "com.qoder.gzh-subscribe"
PLIST_DIR = Path.home() / "Library" / "LaunchAgents"

DEFAULT_CATEGORIES = ["竞对账号", "同类账号", "关注账号"]

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 655)May include surrounding context.

python
MAX_SUBSCRIPTIONS = 20
DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderGzhReports"

PLIST_LABEL = "com.qoder.gzh-subscribe"
PLIST_DIR = Path.home() / "Library" / "LaunchAgents"

DEFAULT_CATEGORIES = ["竞对账号", "同类账号", "关注账号"]

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 710)May include surrounding context.

python
MAX_SUBSCRIPTIONS = 20
DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderGzhReports"

PLIST_LABEL = "com.qoder.gzh-subscribe"
PLIST_DIR = Path.home() / "Library" / "LaunchAgents"

DEFAULT_CATEGORIES = ["竞对账号", "同类账号", "关注账号"]

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill installs OS-level scheduled tasks via LaunchAgents or crontab, which creates persistence beyond simple one-shot article fetching. While framed as a convenience feature, persistence is security-sensitive because it causes recurring execution and expands the blast radius if the script or its dependencies are later modified or compromised.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
94% confidence
Finding

This function explicitly implements persistent scheduled execution via LaunchAgents. Persistence is security-relevant because it causes the code to run automatically in the future and can preserve access to API-backed functionality without additional user approval each time.

Content

Scanner excerpt · assets/subscribe.py (reported line 633)May include surrounding context.

python
def install_subscription():
    """安装定时任务,每天自动拉取并生成日报"""
    if sys.platform == "darwin":
        PLIST_DIR.mkdir(parents=True, exist_ok=True)
        plist_path = PLIST_DIR / f"{PLIST_LABEL}.plist"

        script_path = os.path.abspath(__file__)

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

Creating a plist path in LaunchAgents is part of establishing user-level persistence. In context, this broadens the skill from a simple fetch/report tool into software that modifies autorun configuration on the host.

Content

Scanner excerpt · assets/subscribe.py (reported line 634)May include surrounding context.

python
"""安装定时任务,每天自动拉取并生成日报"""
    if sys.platform == "darwin":
        PLIST_DIR.mkdir(parents=True, exist_ok=True)
        plist_path = PLIST_DIR / f"{PLIST_LABEL}.plist"

        script_path = os.path.abspath(__file__)
        log_path = str(Path.home() / "Library" / "Logs" / "qoder-gzh-subscribe.log")

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

Creating a plist path in LaunchAgents is part of establishing user-level persistence. In context, this broadens the skill from a simple fetch/report tool into software that modifies autorun configuration on the host.

Content

Scanner excerpt · assets/subscribe.py (reported line 634)May include surrounding context.

python
"""安装定时任务,每天自动拉取并生成日报"""
    if sys.platform == "darwin":
        PLIST_DIR.mkdir(parents=True, exist_ok=True)
        plist_path = PLIST_DIR / f"{PLIST_LABEL}.plist"

        script_path = os.path.abspath(__file__)
        log_path = str(Path.home() / "Library" / "Logs" / "qoder-gzh-subscribe.log")

Session Persistence

Medium
Category
Rogue Agent
Confidence
97% confidence
Finding

The generated LaunchAgent embeds the API key into the plist's EnvironmentVariables section, which stores a secret on disk in the user's home directory. This increases credential exposure risk because local users, backups, logs, or other software with file access may recover the secret and abuse the external API account.

Content

Scanner excerpt · assets/subscribe.py (reported line 650)May include surrounding context.

python
<string>{api_key}</string>
        </dict>"""

        plist_content = f'''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 651)May include surrounding context.

python
</dict>"""

        plist_content = f'''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 652)May include surrounding context.

python
</dict>"""

        plist_content = f'''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 676)May include surrounding context.

python
</dict>"""

        plist_content = f'''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · assets/subscribe.py (reported line 710)May include surrounding context.

python
</dict>"""

        plist_content = f'''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>

Static analysis

No suspicious patterns detected.