Back to skill

Security audit

文旅小红书信息源

Security checks for vulnerabilities and agentic risk

Overview

The skill performs the advertised Xiaohongshu report workflow, but subscription mode adds persistent scheduled execution and unsafe handling of commands, credentials, and generated HTML.

Review carefully before installing. Normal report generation will call RedFox with your API key, write local HTML reports, and open them in a browser. Avoid using subscription mode until it is fixed, because it installs recurring jobs and may persist your API key; use a revocable low-scope key and rotate it if you already subscribed.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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 (5)

T06 · System Persistence

Warning
Location
scripts/cultural_tourism_xiaohongshu_report.py:505
Finding
Persistent Scheduled Execution Through LaunchAgent or Crontab<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_xiaohongshu_report.py:505-568` **Vulnerability Type**: Persistent scheduled task installation **Risk Level**: Medium ### Technical Analysis The optional subscription function installs a recurring task that survives the initiating Skill session. On macOS, it writes a property list to the user's `~/Library/LaunchAgents` directory and loads it with `launchctl`. On other supported platforms, it modifies the user's crontab. ```python def install_subscription(keyword): 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-cultural-tourism-xiaohongshu-feed.log") # ... plist_path.write_text(plist_content, encoding="utf-8") try: subprocess.run( ["launchctl", "load", str(plist_path)], check=True, capture_output=True ) return True except subprocess.CalledProcessError as e: error(f"订阅安装失败: {e.stderr.decode()}") return False else: script_path = os.path.abspath(__file__) cron_line = f"0 9 * * * /usr/bin/python3 {script_path} --keyword {keyword} --no-open" try: subprocess.run( f'(crontab -l 2>/dev/null; echo "{cron_line}") | crontab -', shell=True, check=True, capture_output=True ) return True except subprocess.CalledProcessError: return False ``` Daily subscription is an advertised feature and is only reached when `--subscribe` is supplied, so the persistence is not covert. Nevertheless, installing a cross-session scheduler exceeds the privileges required for a one-time search and report operation. Once installed, the task repeatedly execute ...[truncated 955 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require explicit, informed confirmation immediately before installing the scheduled task. - Display the exact command, execution time, credential source, output location, and removal procedure. - Prefer a platform scheduler API rather than constructing scheduler configuration through shell commands. - Copy the executable to a controlled, integrity-protected location or verify the script's hash before every scheduled execution. - Record subscription state and provide a reliable, idempotent uninstallation path. - Avoid duplicate crontab entries and verify ownership and permissions of all generated scheduler files. - Consider generating reports on demand by default and treating scheduling as a separate installation operation. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cultural_tourism_xiaohongshu_report.py:560
Finding
Shell Command Injection Through the Subscription Keyword<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_xiaohongshu_report.py:560-566` **Vulnerability Type**: OS command injection **Risk Level**: Critical ### Technical Analysis The user-controlled `keyword` value and the script path are interpolated into a crontab line. That line is then embedded inside a second shell command and executed with `shell=True`. ```python else: script_path = os.path.abspath(__file__) cron_line = f"0 9 * * * /usr/bin/python3 {script_path} --keyword {keyword} --no-open" try: subprocess.run( f'(crontab -l 2>/dev/null; echo "{cron_line}") | crontab -', shell=True, check=True, capture_output=True ) ``` No shell quoting, escaping, or input validation is applied. A keyword containing a double quote followed by shell metacharacters can terminate the `echo` argument and introduce a new shell command. For example, a value structurally equivalent to: ```text "; attacker_command; # ``` can cause `attacker_command` to be interpreted by `/bin/sh` while the subscription is being installed. The attack does not need to wait for the scheduled task to run. The same construction can also write malicious syntax into the installed crontab, allowing both immediate execution and recurring execution. ### Attack Path 1. An attacker persuades a user or agent to subscribe using a crafted cultural-tourism keyword. 2. The crafted keyword is accepted by `argparse` without validation. 3. `install_subscription()` concatenates it into `cron_line`. 4. The resulting string is concatenated into an `echo` pipeline. 5. `subprocess.run(..., shell=True)` passes the complete string to the system shell. 6. Shell metacharacters in the keyword terminate the intended command and execute attacker-controlled commands. 7. The injected content may additionally be retained in crontab for recurring execution. ### Impact Assessment The attacker can execute arbitrary operating-system commands wit ...[truncated 372 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `shell=True` completely. - Retrieve the existing crontab with an argument-array invocation such as `subprocess.run(["crontab", "-l"], ...)`. - Construct the updated crontab as data and pass it to `subprocess.run(["crontab", "-"], input=..., text=True)`. - Quote every cron command argument with `shlex.quote`, including the interpreter path, script path, and keyword. - Validate keywords against a conservative length and character policy before scheduler installation. - Reject line breaks, null bytes, control characters, quotes, backticks, command substitutions, and shell metacharacters. - Add automated tests using adversarial keywords containing quotes, semicolons, pipes, substitutions, and newlines. - Use a structured scheduling library where available instead of manually serializing cron commands. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cultural_tourism_xiaohongshu_report.py:343
Finding
Unescaped API and User Data in Automatically Opened HTML Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_xiaohongshu_report.py:343-384` **Vulnerability Type**: HTML injection and script execution **Risk Level**: High ### Technical Analysis Post titles, authors, post URLs, cover URLs, publication categories, and the search keyword are inserted directly into HTML markup without contextual escaping. URL values are also not restricted to safe schemes or expected hosts. ```python for article in cluster["articles"]: title = article.get("title", "-") or "-" url = get_work_url(article) or "#" author = article.get("userName") or "" cover = article.get("coverUrl") or "" if cover: cover_html = ( '<img class="article-cover" src="' + cover + '" alt="" loading="lazy" referrerpolicy="no-referrer"' ' onerror="this.outerHTML=\'<div class=&quot;article-cover article-cover-placeholder&quot;></div>\'">' ) else: cover_html = '<div class="article-cover article-cover-placeholder"></div>' articles_html += ( '<div class="article-item">' + cover_html + '<div class="article-info">' + '<a href="' + url + '" target="_blank" class="article-title">' + title + '</a>' + '<div class="article-meta">' + '<span class="author">' + author + '</span>' + '<span class="metrics">' + '<span class="metric">&#x1f44d; ' + likes + '</span>' + '<span class="metric">&#x1f4ac; ' + comments + '</span>' + '<span class="metric">&#x1f501; ' + shares + '</span>' + time_html + '</span></div></div></div>' ) cards_html += f''' <div class="category-card reveal"> <div class="card-header"> <span class="card-number">{i:02d}</span> <h3 class="card-category">{cluster["category"]}</h3> <span class="card-count">{cluster["count"]} 篇</span> </div> <div class="card-body">{articles_html} </div> </div>''' ``` The keyword is ...[truncated 1834 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Apply `html.escape(value, quote=True)` to every text and attribute value derived from users or the API. - Use a template engine configured with automatic HTML escaping instead of string concatenation. - Parse URLs with `urllib.parse.urlsplit`. - Permit only `https` links and restrict work links to expected Xiaohongshu hosts. - Restrict image URLs to `https` and, where feasible, to explicitly trusted image hosts. - Reject `javascript:`, `data:`, `file:`, and other unexpected URL schemes. - Add `rel="noopener noreferrer"` to links opened with `target="_blank"`. - Add a restrictive Content Security Policy that disables inline scripts and event handlers and limits image, style, font, and connection destinations. - Do not automatically open reports containing untrusted remote data unless the user has explicitly requested it. - Add tests covering quotes, angle brackets, event handlers, closing tags, and malicious URL schemes in every API field. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cultural_tourism_xiaohongshu_report.py:510
Finding
API Key Written in Plaintext to a Persistent LaunchAgent File<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_xiaohongshu_report.py:510-550` **Vulnerability Type**: Plaintext credential storage **Risk Level**: High ### Technical Analysis When the RedFox API key is present in the environment during macOS subscription installation, the script copies it into the generated LaunchAgent property list. ```python env_section = "" api_key = os.environ.get(ENV_KEY) if api_key: env_section = ( '\n <key>EnvironmentVariables</key>' '\n <dict>' f'\n <key>{ENV_KEY}</key>' f'\n <string>{api_key}</string>' '\n </dict>' ) plist_content = f'''<?xml version="1.0" encoding="UTF-8"?> <!-- omitted static property-list declarations --> <plist version="1.0"> <dict> <key>Label</key> <string>{PLIST_LABEL}</string> <!-- omitted static scheduler fields --> <key>RunAtLoad</key> <false/>{env_section} </dict> </plist>''' plist_path.write_text(plist_content, encoding="utf-8") ``` `Path.write_text()` does not explicitly enforce restrictive permissions. The resulting file persists under `~/Library/LaunchAgents` and can be copied by backups, diagnostic collectors, malware, or another process able to read the user's files. This behavior also conflicts with the documentation's instruction not to expose the key in output files. Although the API key is legitimately required for authenticated requests to `https://redfox.hk`, persistently embedding it in scheduler configuration is not necessary. ### Attack Path 1. The user exports `REDFOX_API_KEY`. 2. The user or agent invokes subscription installation on macOS. 3. The script reads the key from the environment. 4. The key is serialized as plaintext into the LaunchAgent plist. 5. The plist remains on disk across sessions. 6. A local process, backup reader, support bundle, or account-level attacker reads the file and recovers the credential. 7. The recovered key is ...[truncated 481 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not place the API key in the LaunchAgent plist. - Store the credential in the operating system's credential manager, such as macOS Keychain, and retrieve it at runtime. - Use the narrowest possible API scope and support expiration, revocation, and rotation. - If file-based storage is unavoidable, create a dedicated credential file atomically with mode `0600`, verify ownership, and keep it outside report and scheduler files. - Explicitly set restrictive permissions on generated scheduler files. - Avoid accepting secrets through `--api-key`, because command-line arguments may be visible in process listings or shell history. - Document where credentials are stored and remove stored credentials during uninstallation when the user requests it. - Add a migration routine that detects and removes API keys from previously generated plist files. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cultural_tourism_xiaohongshu_report.py:510
Finding
Unsafe XML Construction for the macOS LaunchAgent<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_xiaohongshu_report.py:510-550` **Vulnerability Type**: XML injection in persistent scheduler configuration **Risk Level**: High ### Technical Analysis The LaunchAgent property list is constructed by interpolating the API key and user-controlled keyword directly into XML text. ```python api_key = os.environ.get(ENV_KEY) if api_key: env_section = ( '\n <key>EnvironmentVariables</key>' '\n <dict>' f'\n <key>{ENV_KEY}</key>' f'\n <string>{api_key}</string>' '\n </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> <string>{PLIST_LABEL}</string> <key>ProgramArguments</key> <array> <string>/usr/bin/python3</string> <string>{script_path}</string> <string>--keyword</string> <string>{keyword}</string> <string>--no-open</string> </array> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>9</integer> <key>Minute</key> <integer>0</integer> </dict> <key>StandardOutPath</key> <string>{log_path}</string> <key>StandardErrorPath</key> <string>{log_path}</string> <key>RunAtLoad</key> <false/>{env_section} </dict> </plist>''' plist_path.write_text(plist_content, encoding="utf-8") subprocess.run(["launchctl", "load", str(plist_path)], check=True, capture_output=True) ``` XML metacharacters such as `<`, `>`, `&`, and quotation-related payloads are not escaped. A crafted keyword can close its `<string>` element and introduce additional property-list nodes. Depending on how the property-list parser handles duplicate or injected keys, this may corrupt the subscription, modify scheduler properties, or alter th ...[truncated 1392 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace manual XML construction with Python's `plistlib`. - Build the property list as native dictionaries, arrays, strings, integers, and booleans, then call `plistlib.dump`. - Validate keyword length and reject control characters before generating scheduler data. - Never interpolate credentials or user values into XML source. - Parse the generated plist with `plistlib.load` and verify the expected schema before invoking `launchctl`. - Verify that `ProgramArguments` contains only the intended interpreter, script, fixed flags, and one literal keyword value. - Write the plist atomically and enforce restrictive ownership and permissions. - Add tests containing XML metacharacters and attempted closing-tag payloads. ]]>
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
96% confidence
Finding
The documented purpose says the skill searches Xiaohongshu travel content and generates an HTML report, but the behavior also includes persistence via scheduled tasks, automatic browser launching, and local secret retrieval from environment/config files. This mismatch undermines informed user consent and can lead to unexpected persistence, local data access, and command execution beyond the advertised function.

Hidden Instructions

High
Category
Prompt Injection
Content
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文旅小红书信息源 - {{KEYWORD}} - {{DATE}}</title>

<!-- Fonts: Archivo Black (display) + Space Grotesk (body) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
66; font-size:0.8rem; }'
        '</style></head><body>'
        '<div class="header">'
        '<h1>文旅小红书信息源</h1>'
        '<p>「{{KEYWORD}}」| {{DATE_CN}}</p>'
        '</div>'
        '<div class="warning-banner">⚠️ 受小红书风控规则限制,部分作品链接可能无法正常跳转,您可复制对应作品标题前往小红书 App 搜索查看,感谢理解🙇‍♀️🙇‍♀️</div>'
        '<div class="stats">'
        '<div class="stat-item"><div class="stat-value">{{TOPIC_COUNT}}</div><div class="stat-label">分类</div></div>'
        '<div class="stat-item"><div class="stat-value">{{TOTAL_COUNT}}</div><div class="stat-label">作品</div></div>'
        '<div class="stat-item"><div class="stat-value">{{AVG_LIKES}}</div><div class="stat-label">平均点赞</div></div>'
        '<div class="stat-item"><div class="stat-value">{{AVG_COMMENTS}}</div><div class="stat-label">平均评论</div></div>'
        '<div class="stat-item"><div class="s
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The skill writes LaunchAgent/crontab configuration and executes launchctl/crontab commands, which is far beyond a simple report generator. In agent contexts, such host-level scheduling changes are dangerous because they create persistence and recurring execution pathways that can survive the initial user request.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The subscription installer copies the API key from the environment into a persistent LaunchAgent plist, storing a credential on disk in a recoverable form. This increases exposure to local credential theft, backup leakage, and unintended reuse by other processes or users with access to the file.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
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
            )
Confidence
97% confidence
Finding
The code pipes crontab output through grep using a shell command that interpolates script_path directly. This is a classic tool-parameter abuse pattern because shell interpretation can be influenced by unexpected path characters, causing arbitrary command execution while manipulating persistent scheduler state.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README advertises 'daily subscription support' and scheduled auto-delivery, but it does not prominently warn that this creates persistent recurring behavior. Without a clear warning and consent flow, users may unknowingly enable ongoing jobs that continue making external requests, generating reports, or consuming quota after the initial interaction.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The README says users can 'just describe what you need in natural language' and the skill metadata includes a wide set of trigger phrases, which can cause the skill to activate for loosely related travel or content-analysis requests. Overly broad invocation guidance increases the chance of unintended execution, unnecessary third-party API calls, and accidental data retrieval or report generation the user did not explicitly request.

Natural-Language Policy Violations

Medium
Confidence
87% confidence
Finding
The usage section is written as a Chinese-only natural-language invocation guide and provides only Chinese example utterances, which effectively constrains use to a specific language. There is no indication that other languages are supported or that Chinese is optional, so this can violate the language/locale choice policy.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill performs sensitive actions including shell execution, network access, reading environment/configured API keys, and writing files, but it declares no explicit tool scope or permission boundaries. Without an allowlist, an agent may invoke broader capabilities than users expect, increasing the chance of unauthorized file, network, or shell operations.

Session Persistence

Medium
Category
Rogue Agent
Content
export REDFOX_API_KEY=ak_xxxx

# 方式二:配置文件
mkdir -p ~/.qoder/apis
echo '{"api_key":"ak_xxxx"}' > ~/.qoder/apis/redfox.json
```
Confidence
78% confidence
Finding
The skill instructs users to persist an API key in a local config file under the home directory, creating session persistence of a secret on disk. While common, storing reusable credentials in plaintext-like local files increases exposure if the workstation, account, or other tools can access that path.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill writes an HTML file to disk and states that it must auto-open the report on every run, but this side effect is not surfaced as a prominent user warning in the skill description. Automatic opening of generated HTML can expose users to unexpected local content rendering, privacy leakage via browser behavior, or nuisance/unsafe UX if the report contains untrusted content.

Session Persistence

Medium
Category
Rogue Agent
Content
PAGE_SIZE = 200

DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderReports"
PLIST_LABEL = "com.qoder.cultural-tourism-xiaohongshu-feed"
PLIST_DIR = Path.home() / "Library" / "LaunchAgents"

# ─── 终端颜色 ──────────────────────────────────────────────────────────────────────
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.

Session Persistence

Medium
Category
Rogue Agent
Content
PAGE_SIZE = 200

DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderReports"
PLIST_LABEL = "com.qoder.cultural-tourism-xiaohongshu-feed"
PLIST_DIR = Path.home() / "Library" / "LaunchAgents"

# ─── 终端颜色 ──────────────────────────────────────────────────────────────────────
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.

Session Persistence

Medium
Category
Rogue Agent
Content
PAGE_SIZE = 200

DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderReports"
PLIST_LABEL = "com.qoder.cultural-tourism-xiaohongshu-feed"
PLIST_DIR = Path.home() / "Library" / "LaunchAgents"

# ─── 终端颜色 ──────────────────────────────────────────────────────────────────────
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.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The skill metadata describes a search-and-report workflow, but the code adds persistent daily subscription behavior that alters host state. This expansion of capability is risky because users may invoke a content skill without expecting installation of recurring background tasks.

Session Persistence

Medium
Category
Rogue Agent
Content
# ─── 订阅机制 ──────────────────────────────────────────────────────────────────────
def install_subscription(keyword):
    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-cultural-tourism-xiaohongshu-feed.log")
Confidence
95% confidence
Finding
The install_subscription function is the entry point for creating OS-level persistence. In this skill context, embedding persistence management in a data-reporting tool broadens capability in a way that can surprise users and increase attack surface.

Session Persistence

Medium
Category
Rogue Agent
Content
def install_subscription(keyword):
    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-cultural-tourism-xiaohongshu-feed.log")
Confidence
93% confidence
Finding
This same line contributes to the macOS persistence mechanism by targeting a plist under LaunchAgents. In a content skill, host persistence is outside expected scope and therefore materially riskier.

Session Persistence

Medium
Category
Rogue Agent
Content
def install_subscription(keyword):
    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-cultural-tourism-xiaohongshu-feed.log")
Confidence
93% confidence
Finding
This same line contributes to the macOS persistence mechanism by targeting a plist under LaunchAgents. In a content skill, host persistence is outside expected scope and therefore materially riskier.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The code persists the API key into a LaunchAgent configuration without clearly warning the user that a secret will be stored on disk. Even if functionality works as intended, silent credential persistence violates least surprise and increases operational security risk.

Session Persistence

Medium
Category
Rogue Agent
Content
'\n        </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>
Confidence
92% confidence
Finding
Generating plist content is a direct step in creating a persistent LaunchAgent job. This persistence is more concerning here because the skill also handles API credentials and network access, giving the recurring task continued ability to use those resources.

Session Persistence

Medium
Category
Rogue Agent
Content
)

        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>
Confidence
92% confidence
Finding
This line is part of the same persistent LaunchAgent definition. The concern is not the XML token itself but the installation of a long-lived scheduled task by a report skill.

Session Persistence

Medium
Category
Rogue Agent
Content
)

        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>
Confidence
92% confidence
Finding
This line is part of the same persistent LaunchAgent definition. The concern is not the XML token itself but the installation of a long-lived scheduled task by a report skill.

Session Persistence

Medium
Category
Rogue Agent
Content
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>
    <string>{PLIST_LABEL}</string>
Confidence
91% confidence
Finding
Setting the Label in the plist contributes to making the persistence operational and identifiable to launchctl. In context, it is one component of unauthorized or unexpected long-term host modification.

Session Persistence

Medium
Category
Rogue Agent
Content
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>{PLIST_LABEL}</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/python3</string>
Confidence
91% confidence
Finding
ProgramArguments in the plist define the command that will run repeatedly, completing the persistence setup. This is risky because it enables unattended future execution of the script with network access and report generation behavior.

Static analysis

No suspicious patterns detected.