Back to skill

Security audit

文旅B站信息源

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated reporting purpose, but its subscription feature creates persistent scheduled jobs with unsafe command/XML handling and credential exposure risks.

Review before installing. Use only with a RedFox API key you can revoke, prefer an environment variable over the plaintext config file, avoid `--subscribe` until the scheduler code is fixed, and do not use untrusted keywords. Treat generated HTML reports as untrusted web content because remote API values are inserted into the page and opened automatically.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cultural_tourism_bilibili_report.py:554
Finding
Shell Command Injection and Persistent Cron Injection Through the Subscription Keyword<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_bilibili_report.py`, lines 554–559 **Vulnerability Type**: OS command injection and scheduled-task injection **Risk Level**: Critical ### Vulnerable Code ```python 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 ) ``` ### Technical Analysis The `keyword` value originates from the user-controlled `--keyword` command-line argument and is interpolated directly into a command executed with `shell=True`. Neither the keyword nor `script_path` is validated or safely quoted. The surrounding double quotes do not prevent shell expansion. Shell constructs such as command substitution, backticks, embedded quotes, and newline characters can alter command behavior. Newlines can additionally insert arbitrary cron entries, converting immediate command injection into persistent execution. ### Attack Path 1. An attacker supplies or induces the Agent to use a malicious subscription keyword containing shell syntax. 2. The Agent invokes the script with `--subscribe` and the crafted keyword. 3. `install_subscription()` inserts the keyword into `cron_line`. 4. The complete string is passed to a shell through `subprocess.run(..., shell=True)`. 5. The shell evaluates the injected syntax with the privileges of the user running the Skill. 6. A crafted newline or cron expression can also register an attacker-controlled recurring command. ### Impact Assessment Successful exploitation provides arbitrary command execution under the Agent user's account. The attacker could read or modify user-accessible files, steal credentials, download additional payloads, alter the user's crontab, or establish recurring execution. No administrative privilege is inherently obtained, but the comp ...[truncated 64 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `shell=True` and never construct scheduler commands by concatenating untrusted strings. - Reject keywords containing control characters, especially carriage returns, newlines, null bytes, quotes, backticks, dollar signs, and shell metacharacters. - Generate a crontab file as structured data and install it with an argument-vector call such as `subprocess.run(["crontab", temporary_file], check=True)`. - If cron syntax must be generated, serialize each program argument with a robust quoting strategy and test it against newline injection. - Use a stable identifier or comment to locate and replace the Skill's own entry rather than appending duplicate entries. - Display the exact scheduled command and obtain explicit user confirmation before modifying the crontab. ]]>

T06 · System Persistence

Error
Location
scripts/cultural_tourism_bilibili_report.py:493
Finding
Cross-Session Persistence Through LaunchAgent and Crontab Installation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_bilibili_report.py`, lines 493–560 **Vulnerability Type**: Persistent scheduled-task registration **Risk Level**: High ### Vulnerable Code ```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__) # Plist generation omitted here. 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: return False else: script_path = os.path.abspath(__file__) cron_line = ( f"0 9 * * * /usr/bin/python3 {script_path} " f"--keyword {keyword} --no-open" ) subprocess.run( f'(crontab -l 2>/dev/null; echo "{cron_line}") | crontab -', shell=True, check=True, capture_output=True ) ``` ### Technical Analysis The subscription feature modifies operating-system scheduler state by writing a macOS LaunchAgent or replacing the user's crontab. These tasks survive the current Skill invocation and future Agent sessions. Subscription support is declared and activated only through `--subscribe`, so the persistence is not hidden. Nevertheless, scheduler modification is materially broader than the network and filesystem access needed for ordinary report generation. The scheduled task also executes the script from its existing path without an integrity check. A later replacement or modification of that file changes the code executed by the scheduler. The Linux implementation appends entries without checking whether an equivalent task already exists, allow ...[truncated 838 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require explicit, informed confirmation immediately before modifying scheduler state. - Explain the execution time, executable path, report destination, credential source, and uninstall procedure. - Prefer a host-application scheduler that provides scoped permissions and visible task management. - Use an immutable or integrity-verified executable path for scheduled execution. - Deduplicate existing tasks before installation. - Assign a unique identifier to the task and remove only the exact matching entry during uninstallation. - Offer generation of scheduler instructions as the default, with automatic installation as a separate explicit action. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cultural_tourism_bilibili_report.py:503
Finding
LaunchAgent XML Injection and Plaintext API-Key Persistence<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_bilibili_report.py`, lines 503–541 **Vulnerability Type**: Unsafe plist construction and plaintext secret storage **Risk Level**: High ### Vulnerable Code ```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"?> <!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") ``` ### Technical Analysis The API key and user-controlled keyword are interpolated into XML without XML escaping. A keyword containing closing tags can break out of its intended `<string>` element and alter the resulting LaunchAgent configuration. Other paths are also inserted without structured serialization. When `REDFOX_API_KEY` is present in the environment, its value is copied into a persistent plist in plaintext. This contradicts the documentation's instruction not to expose the key in output or configuration files. The cod ...[truncated 969 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Generate plist files with Python's `plistlib` rather than string interpolation. - Treat the keyword, script path, log path, and all other external values as untrusted structured data. - Do not copy API keys from the environment into persistent scheduler files. - Store credentials in the operating system keychain and retrieve them at runtime through a narrowly scoped helper. - If a credential file is unavoidable, enforce owner-only permissions and provide rotation and revocation guidance. - Create the plist atomically and explicitly set its mode to `0600`. - Validate the generated plist before registering it and remove it if registration fails. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cultural_tourism_bilibili_report.py:340
Finding
Stored HTML Injection in Automatically Opened Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cultural_tourism_bilibili_report.py`, lines 340–384 **Vulnerability Type**: Stored HTML injection and unsafe URL handling **Risk Level**: High ### Vulnerable Code ```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>' ) ``` Related user-controlled insertion and automatic opening occur at lines 438–448 and 716–733: ```python if keyword: keyword_badge = '<div class="keyword-badge">「' + keyword + '」</div>' html = html.replace("{{KEYWORD_BADGE}}", keyword_badge) html = html.replace("{{KEYWORD}}", keyword or "全部") ``` ```python output_path.write_text(html_content, encoding="utf-8") if not args.no_open: if sys.platform == "darwin": subprocess.Popen(["open", file_path]) elif sys.platform == "li ...[truncated 1746 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Apply `html.escape(value, quote=True)` to every untrusted value inserted into HTML. - Use a real templating engine with automatic escaping rather than string concatenation. - Parse all URLs and permit only explicitly approved schemes, preferably `https`. - Consider restricting work and cover URLs to expected Bilibili or approved content-delivery hosts. - Add `rel="noopener noreferrer"` to links opened with `target="_blank"`. - Use a restrictive Content Security Policy that blocks inline script and limits image and connection destinations. - Avoid inline event handlers such as `onerror`. - Make automatic report opening opt-in, especially when reports contain remote data. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:31
Finding
Credential Setup Instructions Create an Unprotected Plaintext API-Key File<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 31–33 **Vulnerability Type**: Insecure plaintext credential storage guidance **Risk Level**: Medium ### Vulnerable Code ```bash mkdir -p ~/.qoder/apis echo '{"api_key":"ak_xxxx"}' > ~/.qoder/apis/redfox.json ``` ### Technical Analysis The documented setup alternative stores the API key in a plaintext JSON file without explicitly setting restrictive directory or file permissions. The resulting permissions depend on the user's current `umask`. On permissively configured systems, other local users or processes may be able to read the credential. The script subsequently trusts and reads this file as an authentication source. ### Attack Path 1. A user follows the documented configuration command. 2. The shell creates the directory and credential file using permissions derived from the current `umask`. 3. Another local principal or compromised process reads `~/.qoder/apis/redfox.json`. 4. The recovered key is used to access the RedFox API within the key's assigned scope. ### Impact Assessment The exposure is limited to the privileges of the RedFox API key and requires local file access. Depending on the key's scope, an attacker may consume API quota, access associated API data, or impersonate the user to the service. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Prefer an operating-system credential manager or keychain. - If file storage is necessary, document commands that enforce owner-only permissions: ```bash install -d -m 700 ~/.qoder/apis umask 077 printf '%s\n' '{"api_key":"ak_xxxx"}' > ~/.qoder/apis/redfox.json chmod 600 ~/.qoder/apis/redfox.json ``` - Validate file ownership and permissions before reading the key. - Warn users and refuse to use credential files writable or readable by unintended principals. - Document credential rotation and revocation procedures. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:98
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 98–102 **Vulnerability Type**: Unpinned package installation **Risk Level**: Low ### Vulnerable Code ```bash pip3 install requests ``` ### Technical Analysis The dependency installation instruction retrieves the currently published version of `requests` and its unresolved transitive dependencies without version constraints or integrity hashes. The package name is legitimate and no dependency confusion or typosquatting was identified, but installations are not reproducible and implicitly trust future package releases and index responses. ### Attack Path 1. A user follows the dependency installation instruction. 2. `pip` resolves the latest available package and transitive dependency versions. 3. A compromised release, package-index account, mirror, or dependency is downloaded. 4. Malicious installation or runtime code executes with the privileges of the user running `pip` or the Skill. ### Impact Assessment The practical likelihood is low for the well-known `requests` package, but a supply-chain compromise could execute arbitrary code under the installing user's account. The affected scope includes user-accessible files, environment variables, and network credentials available during installation or execution. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin reviewed package and transitive dependency versions in a requirements or lock file. - Include cryptographic hashes and install with `pip --require-hashes`. - Use a dedicated virtual environment rather than the system Python environment. - Review and update pinned versions through a controlled dependency-update process. - Use a trusted package index and retain vulnerability-scanning records for the selected versions. ]]>
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 (45)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared behavior understates several materially sensitive actions: installing/removing scheduled tasks, automatically opening local HTML in a browser, relying on a third-party API, and using ranking logic different from the description. This mismatch undermines informed user consent and review, and can hide persistence or external data exfiltration behaviors behind an apparently simple reporting skill.

Hidden Instructions

High
Category
Prompt Injection
Content
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文旅B站信息源 - {{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.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
This code performs system-level installation and removal of scheduled jobs, creating persistence on the host outside the narrow expectation of a search/report skill. In this context, the capability is more dangerous because it alters user environment state and, on Linux, is partly implemented with unsafe shell construction.

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
99% confidence
Finding
The shell command used to edit crontab includes interpolated script_path inside double quotes and runs with shell=True. If the path contains shell metacharacters or command substitutions, an attacker can abuse tool parameters to execute unintended commands or corrupt the user's crontab.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The README says users can 'Just describe what you need in natural language' and then provides broad example phrasings, but it does not define specific trigger conditions, exclusions, or scope boundaries. This makes activation ambiguous and increases the chance of unintended invocation from everyday analytical requests about Bilibili or tourism topics.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The README instructs users to invoke the skill with very broad natural-language phrases like '看看B站最新文旅爆款' and '订阅B站文旅日报', without clear constraints or explicit confirmation boundaries. In an agent ecosystem, this can cause unintended activation when a user mentions similar topics conversationally, potentially triggering external data retrieval, report generation, or subscriptions without sufficiently deliberate intent.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes shell, network, filesystem, and environment-variable access but does not declare any explicit tool scope or permissions. This weakens least-privilege controls and makes it harder for a host agent or reviewer to understand and constrain what the skill is allowed to do, increasing the risk of unintended command execution, local file writes, or secret exposure.

Vague Triggers

Medium
Confidence
92% confidence
Finding
Broad trigger phrases such as generic travel-related terms increase the chance that the skill activates in contexts where the user did not intend it. Because the skill performs network access, file generation, browser launching, and possible subscription setup, unintended activation can lead to unnecessary side effects and privacy exposure.

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
88% confidence
Finding
The skill instructs users to store a long-lived API key in a persistent file under the home directory. Persisting secrets in a predictable local path increases the chance of accidental disclosure to other tools, backups, logs, or compromised local processes, especially when the skill also uses shell and file operations.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill requires automatic browser opening and supports daily subscription behavior, but the description does not clearly warn users about these side effects before execution. Hidden side effects reduce transparency and can surprise users with local application launches or persistent scheduled jobs.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The HTML document is explicitly fixed to the `zh-CN` locale via the `lang` attribute. Under the policy for natural-language violations, forcing a specific language or locale without user opt-in or a documented region-specific justification is a reportable issue.

Session Persistence

Medium
Category
Rogue Agent
Content
PAGE_SIZE = 200

DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderReports"
PLIST_LABEL = "com.qoder.cultural-tourism-bilibili-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-bilibili-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.

Intent-Code Divergence

Medium
Confidence
99% confidence
Finding
The script inserts untrusted title, author, cover URL, and work URL values directly into generated HTML attributes and element bodies without escaping. If the upstream API returns crafted content, opening the local report can trigger script execution or malicious markup in the user's browser, turning the report into a stored XSS-style local HTML attack.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The skill adds persistent scheduled-task installation behavior that is not reflected in the manifest's feed/reporting description, which expands the trust boundary unexpectedly. In an agent-skill context, hidden persistence is especially risky because users may invoke a content-report skill without realizing it can modify long-lived system automation.

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-bilibili-feed.log")
Confidence
95% confidence
Finding
This line begins the macOS LaunchAgent installation flow by creating the persistence directory and preparing a plist path. It is part of a feature that establishes recurring execution on the host, which is sensitive in this skill context.

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-bilibili-feed.log")
Confidence
95% confidence
Finding
This constructs the LaunchAgent plist path used to persist the skill across sessions. While not executable by itself, it is an integral step in setting up recurring host execution.

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-bilibili-feed.log")
Confidence
95% confidence
Finding
This constructs the LaunchAgent plist path used to persist the skill across sessions. While not executable by itself, it is an integral step in setting up recurring host execution.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The macOS subscription path embeds the API key into a LaunchAgent plist, creating another persistent plaintext secret location without warning the user. This increases exposure of the credential to local disclosure via filesystem access, backups, or accidental sharing of configuration files.

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
95% confidence
Finding
This begins building the LaunchAgent plist content used for persistence. The risk is the creation of a scheduled, recurring execution artifact for a skill whose primary purpose appears to be ad hoc reporting.

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
95% confidence
Finding
This continues construction of the persistent LaunchAgent definition. In context, it contributes to unattended future execution and therefore represents persistence capability.

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
95% confidence
Finding
This continues construction of the persistent LaunchAgent definition. In context, it contributes to unattended future execution and therefore represents persistence capability.

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
95% confidence
Finding
The plist declaration here is part of assembling a LaunchAgent that causes recurring execution. Persistence is the core concern, not this XML syntax itself.

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
95% confidence
Finding
This line adds ProgramArguments to the LaunchAgent, defining what will run automatically later. That makes the persistence concrete and therefore security-relevant in a user workstation context.

Session Persistence

Medium
Category
Rogue Agent
Content
<key>RunAtLoad</key>
    <false/>{env_section}
</dict>
</plist>'''

        plist_path.write_text(plist_content, encoding="utf-8")
        try:
Confidence
96% confidence
Finding
Writing the plist to the LaunchAgents directory creates the persistence artifact on disk. This is a substantive state change that outlives the current process and should be treated as a true persistence risk.

Static analysis

No suspicious patterns detected.