Back to skill

Security audit

RSS Aggregator

Security checks for vulnerabilities and agentic risk

Overview

This RSS skill is mostly a straightforward feed-fetching and automation guide, but users should be careful with scheduled forwarding and untrusted feed content.

Install this only if you are comfortable running a Python feed fetcher and, if you use the recipes, creating scheduled jobs that may send article titles, links, and summaries to Discord, webhooks, or Notion. Prefer public feeds, avoid internal/private feed URLs, pin dependencies in a virtual environment, and treat feed text as untrusted when summarizing or posting it.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_feeds.py:16
Finding
Unrestricted Resource Fetching Enables SSRF and Local Resource Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_feeds.py:16-18` **Vulnerability Type**: Unrestricted URL and resource fetching **Risk Level**: Medium ### Vulnerable Code ```python def fetch_feed(url, max_age_days=None, keyword_filter=None): """Fetch and filter feed entries.""" feed = feedparser.parse(url) ``` The URL originates directly from a command-line argument at `scripts/fetch_feeds.py:42-54`: ```python if __name__ == '__main__': url = sys.argv[1] if len(sys.argv) > 1 else '' max_age = int(sys.argv[2]) if len(sys.argv) > 2 else None keyword = sys.argv[3] if len(sys.argv) > 3 else None if not url: print(json.dumps({'error': 'URL required'})) sys.exit(1) result = fetch_feed(url, max_age, keyword) print(json.dumps(result, indent=2)) ``` ### Technical Analysis The script passes a caller-controlled resource identifier directly to `feedparser.parse()` without validating the scheme, destination host, resolved IP address, redirects, or whether the input is a local path. Depending on the schemes and handlers supported by the installed parser and Python runtime, this can allow: - Requests to loopback services such as `127.0.0.1`. - Requests to private or link-local network addresses. - Access to cloud instance metadata endpoints. - Parsing of local files or paths accessible to the process. - Redirect-based bypasses in which an initially acceptable URL redirects to a restricted destination. Any resulting document that can be interpreted as feed data may be included in the JSON output. The documented scheduling and webhook workflows can subsequently transmit that output to another service. ### Attack Path 1. An attacker, untrusted user, or compromised Agent workflow supplies a malicious feed resource as the first command-line argument. 2. The script forwards the value to `feedparser.parse()` without validation. 3. The parser accesses an internal service, link-local endpoint, or local r ...[truncated 999 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the input with `urllib.parse.urlsplit` and allow only explicitly required schemes, preferably `https`. 2. Reject local paths, `file:` URLs, embedded credentials, malformed hostnames, and nonstandard schemes. 3. Resolve the destination hostname before connecting and reject: - Loopback addresses. - Private network addresses. - Link-local addresses. - Multicast, reserved, and unspecified addresses. 4. Revalidate the destination after every redirect to prevent redirect-based SSRF bypasses. 5. Use a controlled HTTP client with explicit connection and read timeouts. 6. Set maximum redirect, response-size, and entry-count limits. 7. Consider an allowlist of approved feed domains for scheduled jobs. 8. Run the process in a sandbox with restricted filesystem and network access. 9. Avoid automatically forwarding fetched data to external services unless the destination and content have been validated. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_feeds.py:29
Finding
Untrusted Feed Content Can Cause Indirect Prompt Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_feeds.py:29-39` **Vulnerability Type**: Untrusted content passed into Agent-driven workflows **Risk Level**: Medium ### Vulnerable Code ```python return { 'title': feed.feed.get('title', url), 'url': url, 'entries': [ { 'title': e.get('title', 'No title'), 'link': e.get('link', ''), 'published': parse_date(e).isoformat() if parse_date(e) else None, 'summary': e.get('summary', e.get('description', ''))[:500] } for e in entries ] } ``` The documented recipes subsequently direct an Agent to summarize and route these fields. For example, `SKILL.md:70-78` instructs the Agent to run the script and summarize the returned stories. ### Technical Analysis RSS and Atom titles, summaries, descriptions, and links are controlled by feed publishers. The script emits this content without trust labels, content normalization, markup sanitization, or controls designed to keep the content separate from Agent instructions. A malicious feed entry can therefore contain text such as purported system instructions, requests to invoke tools, directions to reveal data, or deceptive output-format commands. When the result is inserted into an Agent context for summarization, the model may interpret this data as instructions rather than as untrusted source material. The summary field is limited to 500 characters, but entry titles and links are not length-limited. Truncation alone does not prevent prompt injection because an effective instruction can be short. ### Attack Path 1. An attacker controls a monitored feed or succeeds in publishing an entry to a monitored source. 2. The attacker embeds adversarial instructions in the feed title, summary, description, or link. 3. A scheduled workflow runs `fetch_feeds.py` and places those fields in its JSON output. 4. The Agent receive ...[truncated 1190 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every feed field as untrusted data and label it accordingly before including it in an Agent prompt. 2. Place feed content inside strongly delimited data blocks and explicitly instruct the Agent not to follow instructions found inside those blocks. 3. Use a data-only summarization stage that has no tool access, credentials, memory-writing capability, or outbound integration permissions. 4. Validate entry links and allow only expected `http` or `https` schemes. 5. Apply strict length limits to feed titles, links, summaries, feed names, and the number of entries. 6. Strip or sanitize HTML, scripts, control characters, hidden text, and misleading markup before further processing. 7. Construct outbound Discord, Notion, and webhook messages from a fixed template rather than allowing feed content to determine commands or formatting. 8. Require confirmation before any feed-derived text can cause a sensitive tool call or external action. 9. Keep secrets and unrelated session context unavailable to the summarization Agent. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:15
Finding
Unpinned Third-Party Dependency Creates Supply-Chain Risk<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:15-19` **Vulnerability Type**: Unpinned dependency installation **Risk Level**: Low ### Vulnerable Code ```bash pip install feedparser ``` ### Technical Analysis The installation command does not constrain `feedparser` to a reviewed version and does not verify package hashes. Consequently, installation behavior may change over time as the package index resolves different releases. This makes the environment non-reproducible and exposes installation to supply-chain events such as a compromised future release, package index compromise, unsafe dependency resolution, or an unexpected incompatible version. No evidence was found that the current `feedparser` package is malicious; the issue is the absence of version and integrity controls. ### Attack Path 1. A user follows the setup instructions and runs the unpinned `pip install feedparser` command. 2. The package installer resolves the version available from its configured package index at that time. 3. If the package source, account, release, index, or dependency chain has been compromised, attacker-controlled package content is downloaded. 4. Malicious installation or runtime code executes with the privileges of the user or environment running `pip` or the Skill. 5. The compromised package can affect feed processing and access resources available to that Python environment. ### Impact Assessment The potential impact is determined by the privileges used to install and run the dependency. In a normal virtual environment, compromise would generally affect that environment and data accessible to its user. If installation is performed with administrative privileges, the impact could extend system-wide. Potential consequences include: - Arbitrary code execution under the installer or runtime account. - Access to environment variables, files, and credentials available to that account. - Manipulation of feed results. - Network access from the host ...[truncated 176 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `feedparser` to a specifically reviewed version. 2. Record and verify package hashes using a requirements file, for example through `pip install --require-hashes`. 3. Use a lock file generated from a controlled dependency-resolution process. 4. Install dependencies inside a dedicated, nonprivileged virtual environment. 5. Configure an approved package index or internal package mirror. 6. Regularly scan pinned dependencies for known vulnerabilities and deliberately review upgrades. 7. Avoid running `pip` with root or administrator privileges. 8. Preserve a software bill of materials for deployed Skill environments. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The code partially aligns with the declared description because it does fetch RSS/Atom feeds and supports simple filtering by age and keyword. However, the declared purpose emphasizes a broader feed-monitoring/aggregation system with scheduled operation, alerts/digests, and routing to external destinations. None of those core capabilities appear in the supplied code. The implementation is limited to one-shot retrieval of a single feed URL and JSON printing. This is a material underimplementation relative to the declared behavior, so it should be flagged as a mismatch.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill promotes sending fetched article content and summaries to external services such as Discord, webhooks, and Notion without an explicit warning that feed contents, URLs, and derived summaries will leave the local environment. That can cause unintentional data disclosure, especially if users monitor internal, authenticated, or sensitive feeds and assume the skill is only a local aggregator.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This recipe explicitly delivers article data to a Discord webhook but does not warn users that titles, links, and possibly summaries from monitored feeds will be transmitted to a third party. If the monitored feed is private, internal, or contains sensitive URLs or metadata, this creates a realistic exfiltration path through routine automation.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The line 'use替他' introduces non-English text unexpectedly in otherwise English documentation, without offering a language choice or explanation. This can violate language consistency expectations and may confuse users who did not opt into mixed-language content.

Static analysis

No suspicious patterns detected.