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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.