T08 · Insecure Dependencies
- Location
scripts/fetch_rss.py:9- Finding
Unpinned dependency is installed automatically at runtime
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill matches a podcast publishing workflow, but it needs review because it can publish publicly, install a package at runtime, and download Notion-provided URLs without tight limits.
Review this skill before installing. Use it only in an environment where runtime package installation is disabled or pre-provisioned, Notion/image network egress is constrained, and a human explicitly approves any Substack publish or LinkedIn post. Prefer running Notion image fetching with --no-download unless the sources are trusted.
scripts/fetch_rss.py:9Unpinned dependency is installed automatically at runtime
scripts/fetch_rss.py:22User-supplied RSS URLs permit unrestricted server-side network requests
scripts/fetch_notion_episode.py:219Notion-controlled external image URLs are downloaded without destination or size restrictions
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
},
)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
raw = resp.read().decode("utf-8")
return json.loads(raw)
except urllib.error.HTTPError as exc:
The script downloads arbitrary image URLs returned from Notion page content or file properties without validating scheme, host, size, or content type. If an attacker can influence Notion content, this creates an SSRF-style outbound fetch primitive and can also lead to downloading unexpectedly large or non-image payloads to local disk.
for idx, u in enumerate(urls, start=1):
req = urllib.request.Request(u, headers={"User-Agent": USER_AGENT})
try:
with urllib.request.urlopen(req, timeout=40) as resp:
content = resp.read()
ext = infer_ext(u, resp.headers.get("Content-Type"))
except Exception as exc: # pragma: no cover - best effort download
The declared description presents a broader end-to-end workflow: taking podcast data from RSS + Notion, publishing to Substack with reliable Apple Podcasts embedding, extracting images, and generating LinkedIn-ready companion posts. The supplied code only implements the Notion-fetch portion of that pipeline. It queries a Notion data source, selects a page, recursively extracts block text, finds image URLs, optionally downloads images, and emits JSON. While image extraction is consistent with part of the description, the major advertised capabilities—RSS handling, Substack publishing, embed-fix behavior, and LinkedIn post generation—are absent. Therefore the code chunk does not accurately represent the declared overall purpose.
The declared description presents a multi-system automation workflow involving RSS, Notion, Substack publishing, Apple Podcasts embed reliability, image extraction, and LinkedIn post generation. The actual code chunk is much narrower: it parses an RSS feed using feedparser, filters entries by date, extracts episode numbers from titles, and outputs episode metadata as JSON. While RSS fetching is one supporting part of the stated workflow, the code does not implement the primary advertised behaviors or integrations. Therefore the description materially overstates what this code chunk actually does.
The declared description describes a multi-step workflow for transforming podcast content from RSS/Notion into Substack posts with embedding and LinkedIn cross-post generation. The supplied code does none of that. It only echoes a single Apple Podcasts URL from an environment variable or default constant. While Apple Podcasts is mentioned in both, the implementation is far narrower and materially different from the declared primary purpose, and it even ignores the episode_title input rather than producing episode-specific links.
The declared description presents a broader workflow skill centered on publishing podcast episodes from RSS/Notion to Substack, fixing image-fetch and Apple embed issues, and then creating LinkedIn companion posts. The supplied code chunk implements only the last, narrow piece: formatting a LinkedIn-ready post from provided text fields. It performs no network access, no RSS parsing, no Notion integration, no Substack interaction, and no Apple embed reliability logic. Because the actual code's primary purpose is much narrower and omits the core declared publishing/integration behavior, this is a material description-behavior mismatch.
The skill invokes shell commands, reads environment-based secrets, accesses local files, and depends on networked services, but it declares no explicit tool scope or permission boundaries. In an agent environment, this can lead to overbroad execution authority and unintended access to secrets, files, or external systems when the skill is run automatically.
The workflow includes publishing to Substack and posting or queueing LinkedIn content, but the skill text does not prominently warn that it can affect public-facing accounts. In agent-assisted environments, missing disclosure and confirmation requirements can cause unintended publication, reputational damage, and unauthorized changes to external platforms.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
from pathlib import Path
from typing import Any
API = "https://api.notion.com/v1"
NOTION_VERSION = "2025-09-03"
USER_AGENT = "podcast-to-substack-notion-fetcher/1.0"
Installing a Python package at runtime is dangerous because it performs network-dependent code acquisition and execution outside the skill's stated purpose of parsing RSS. In an agent or automation environment, this can lead to unreviewed dependency changes, supply-chain compromise, or unexpected mutation of the host environment.
The script automatically installs feedparser without warning or confirmation, so a caller expecting read-only RSS processing may instead trigger package installation and subprocess execution. That behavior is especially risky in shared, sandboxed, or production environments where unauthorized package changes can weaken isolation or break reproducibility.
The script invokes pip at runtime via a subprocess when feedparser is missing, which introduces unintended code execution and network access during normal use. This expands the trust boundary from a simple RSS fetcher to arbitrary package installation, creating supply-chain and environment integrity risks if the package source, resolver, or execution context is compromised.
import feedparser
except ImportError:
import subprocess
subprocess.check_call([sys.executable, "-m", "pip", "install", "feedparser", "-q"])
import feedparser
The skill states that it uses a Notion API key and fetches scripts and images from Notion, but it does not clearly warn that external content will be accessed and downloaded. This can expose users to unexpected data egress, handling of sensitive workspace content, or ingestion of untrusted remote assets without informed consent.
No suspicious patterns detected.