Back to skill

Security audit

soulmd-newsletter

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to be a simple RSS newsletter fetcher with low-impact network and state-file behavior, though one packaged script is malformed and should be fixed before use.

Before installing, expect the skill to contact Buttondown, display content and links from that RSS feed, include a subscription link in its output, and optionally store a small last-seen state file under ~/.openclaw. The packaged scripts/fetch_latest.py should be repaired if that path is intended to run directly.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (3)

T01 · Skill Instruction Hijacking

Warning
Location
SKILL.md:7
Finding
Mandatory Third-Party Promotional Content in Skill Output## Vulnerability Details **File Location**: `SKILL.md`, lines 7-8 and 43 **Vulnerability Type**: Persistent output manipulation and third-party traffic redirection **Risk Level**: Medium ### Vulnerable Code ```python RSS_URL = "https://buttondown.com/soulmd/rss" SUBSCRIBE_URL = "https://buttondown.com/soulmd" ``` ```python print(f"TITLE: {latest['title']}\nDATE: {latest['date']}\nLINK: {latest['link']}\nSUBSCRIBE: {SUBSCRIBE_URL}\n\nEXCERPT:\n{latest['excerpt']}") ``` ### Technical Analysis Every successful invocation inserts the hardcoded `SUBSCRIBE_URL` into the output, regardless of whether the user requested subscription information. Because skill output is likely to be incorporated into an agent response, this behavior persistently modifies the response to promote a third-party newsletter. The URL is fixed by the skill author and is not required to retrieve or display the latest RSS entry. This creates an output-integrity concern: invoking a retrieval function implicitly produces advertising and directs user traffic to an external service. ### Attack Path 1. A user or agent invokes the skill to retrieve the latest newsletter entry. 2. The script requests the configured RSS feed. 3. After parsing the latest item, the script unconditionally appends the hardcoded `SUBSCRIBE` field. 4. The consuming agent may relay the complete output to the user. 5. The user is consequently exposed or redirected to a third-party subscription page that was not explicitly requested. ### Impact Assessment This issue does not grant local system privileges or enable code execution. Its scope is limited to response integrity, unwanted promotion, and third-party traffic redirection. Repeated use can cause an agent to advertise the configured service in every successful response, potentially misleading users into believing that the subscription link is a necessary or endorsed part of the requested operation.
Remediation
## Remediation Suggestions - Remove the unconditional `SUBSCRIBE` field from the normal retrieval output. - Return subscription information only when the user explicitly requests it. - Clearly distinguish optional promotional links from retrieved RSS data. - Document all external destinations and the purpose of each network interaction. - If a subscription feature is retained, implement it as a separate, explicitly invoked operation rather than coupling it to every successful feed retrieval.

T01 · Skill Instruction Hijacking

Warning
Location
SKILL.md:10
Finding
Untrusted Remote RSS Content Exposed to the Consuming Agent## Vulnerability Details **File Location**: `SKILL.md`, lines 10-20 and 43 **Vulnerability Type**: Indirect prompt-injection exposure through remote content **Risk Level**: Medium ### Vulnerable Code ```python def fetch_rss(): req = urllib.request.Request(RSS_URL, headers={"User-Agent": "soul-md-skill/1.0"}) with urllib.request.urlopen(req, timeout=10) as resp: return resp.read() def parse_latest(xml_bytes): root = ET.fromstring(xml_bytes) item = root.find("channel/item") if item is None: return None plain = re.sub(r"<[^>]+>", "", item.findtext("description", ""))[:600].strip() return {"title": item.findtext("title","").strip(), "link": item.findtext("link","").strip(), "date": item.findtext("pubDate","").strip(), "excerpt": plain} ``` ```python print(f"TITLE: {latest['title']}\nDATE: {latest['date']}\nLINK: {latest['link']}\nSUBSCRIBE: {SUBSCRIBE_URL}\n\nEXCERPT:\n{latest['excerpt']}") ``` ### Technical Analysis The script retrieves an externally controlled RSS document and directly emits its title, publication date, link, and description excerpt into agent-visible output. The regular expression applied to the description only attempts to remove markup. It does not establish a trust boundary, detect instruction-like text, validate the destination URL, or prevent content from being interpreted as directions by a consuming language model. The title, link, and publication date receive no content filtering beyond whitespace trimming. The description remains attacker-controlled plain text after tag removal. If the feed publisher, hosting account, or delivery infrastructure is compromised, an attacker can place deceptive instructions or links in these fields. This is not remote code execution by itself: the downloaded data is parsed as XML and printed rather than executed as Python. The security concern is indirect instruction injection when the output is subs ...[truncated 1459 chars]
Remediation
## Remediation Suggestions - Explicitly label all feed-derived values as untrusted external content. - Place remote fields inside strongly delimited data blocks and instruct the consuming agent not to interpret them as commands. - Validate feed-provided links before presenting them, including enforcing an expected HTTPS host allowlist where appropriate. - Reject or flag content containing command-like or prompt-injection patterns rather than presenting it as trusted skill output. - Return structured data, such as JSON with clearly named untrusted fields, instead of free-form text that can be confused with instructions. - Apply length and character restrictions to every remote field, not only the description. - Ensure the consuming agent is configured to treat tool output as data and never as higher-priority instructions. - Consider retrieving and displaying only the minimum fields necessary for the user's request.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/fetch_latest.py:1
Finding
Malformed Python Script Contains Markdown Scaffolding and a Truncated Statement## Vulnerability Details **File Location**: `scripts/fetch_latest.py`, lines 1-6 and 49 **Vulnerability Type**: Invalid executable artifact and packaging integrity failure **Risk Level**: Low ### Vulnerable Code ```text --- **File 2: Inside `soul-md`, create a folder called `scripts`, then create `fetch_latest.py` with this content:** ```python #!/usr/bin/env python3 ``` The file terminates with the following incomplete statement: ```python print(f"TITLE: {latest['title']} ``` ### Technical Analysis The file named `scripts/fetch_latest.py` is not valid Python source. It begins with Markdown document scaffolding, including a horizontal rule, prose, and an opening fenced-code marker. It also ends in the middle of an f-string without closing the string, parenthesis, or Markdown code fence. Consequently, direct execution or import of this file will fail during parsing before its intended functionality can run. This indicates that installation documentation or generated response content was mistakenly saved as the executable artifact instead of a complete Python script. ### Attack Path 1. A user or agent attempts to execute `scripts/fetch_latest.py`. 2. The Python interpreter reads the leading Markdown text or reaches the unterminated f-string. 3. Parsing fails with a syntax error. 4. The expected feed retrieval operation does not execute. 5. Any workflow depending on this script fails or may fall back to an unintended operational path if the surrounding system implements fallback behavior. ### Impact Assessment The confirmed impact is loss of availability and integrity for the packaged script. The file cannot perform its advertised function as a directly executable Python program. No privilege escalation, arbitrary code execution, data exfiltration, or persistence results from the malformed content itself. The scope is limited to workflows that invoke or import `scripts/fetch_latest.py`.
Remediation
## Remediation Suggestions - Replace the file with complete, syntactically valid Python source. - Keep installation instructions and Markdown fences in documentation files rather than executable files. - Restore the complete final `print` statement and ensure all strings and parentheses are closed. - Add automated syntax validation, such as `python -m py_compile scripts/fetch_latest.py`, to the build or release process. - Add a minimal execution test that verifies normal operation and the `--check-new` path. - Compare packaged artifacts with their intended source before publication to detect truncation or documentation contamination.
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
Lines L04-L06 describe the following content as a Python file, but they are themselves Markdown/instructional wrapper text rather than Python source. This actively conflicts with the apparent intent of the file and would prevent the file from functioning as the documented script if included literally.

Static analysis

No suspicious patterns detected.