Back to skill

Security audit

spotify-news-digest

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate Spotify news digest, but it needs Review because scheduled LLM summarization ingests untrusted news text and its network fetching is not tightly contained.

Install only if you are comfortable with a networked news-fetching skill. Run scheduled jobs in an isolated environment with no internal-service or secret access, keep the source list limited to public news domains, pin and audit dependencies, and ensure the LLM summarizes article fields as untrusted quoted content before posting to any channel.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_spotify_news.py:119
Finding

Configuration-controlled outbound requests enable server-side request forgery

Content
View full analysis
List[Dict]: keyword = source.get('keyword_filter', '').lower() resp = requests.get( source['url'], timeout=self.timeout, headers=HEADERS, verify=True, # Explicit: TLS verification ON ) resp.raise_for_status() ``` The Hacker News API path uses the same unrestricted configuration value: ```python def _fetch_hn(self, source: Dict, cutoff: datetime) -> List[Dict]: resp = requests.get( source['url'], timeout=self.timeout, headers=HEADERS, verify=True, # Explicit: TLS verification ON ) data = resp.json() ``` ### Technical Analysis The request destination is read directly from `sources.json` and passed to `requests.get()` without validating: - The URL scheme - The destination hostname - The resolved IP address - Redirect destinations - Whether the destination is loopback, link-local, private, or reserved TLS verification protects connection authenticity for HTTPS destinations, but it does not prevent requests to unauthorized destinations. The `ALLOWED_DDG_DOMAINS` restriction only filters links returned by DuckDuckGo; it is not applied to RSS or API requests. In addition, `requests.get()` follows redirects by default. A public source can therefore redirect the fetcher to an internal service unless every redirect hop is separately validated. ### Attack Path 1. An attacker causes a crafted source to be added to `config/sources.json`, such as an internal HTTP service, loopback address, or cloud metadata endpoint. This may occur through configuration modification or an unsafe custom-source workflow. 2. Alternatively, an existing public sou ...[truncated 1164 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:143
Finding

Untrusted article content is supplied to the calling LLM without prompt-injection controls

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Open-ended dependency versions prevent reproducible and integrity-controlled installation

Content
View full analysis
=6.0 beautifulsoup4>=4.12 requests>=2.28 python-dateutil>=2.8 ddgs>=7.0 ``` The installation guidance in `SKILL.md` also installs packages without a lockfile or integrity hashes: ```bash pip3 install feedparser beautifulsoup4 requests python-dateutil ddgs ``` ### Technical Analysis Every dependency uses an open-ended minimum version. An installation can therefore resolve to any future package release satisfying the lower bound. The project does not include: - Exact dependency versions - A transitive dependency lockfile - Package hashes - A controlled package index - Provenance or signature verification As a result, installations are not reproducible, and code not present during this audit may be installed and imported at runtime. This is especially relevant because Python packages can execute code during installation and are subsequently imported by the Skill. This finding does not establish that any currently named dependency is malicious. It identifies an unsafe dependency-management configuration that increases exposure to future package compromise or incompatible releases. ### Attack Path 1. A direct or transitive dependency account, release process, or distribution channel is compromised. 2. An attacker publishes a newer package version that still satisfies the declared minimum constraint. 3. A user installs the Skill dependencies at a later date. 4. The package resolver automatically selects the attacker-controlled release because no upper or exact version is specified. 5. Malicious package code executes during installation or when imported by the Skill. 6. The package receives the privileges of the user or service running the installation and digest process. ### Impact Assessment If a resolved dependency is compromised, attacker-controlled Python co ...[truncated 477 chars]
Remediation
View remediation
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (19)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill clearly describes network access, reading local configuration, and optional file output, but it does not declare any explicit tool scope or permissions boundary. In an agent platform, missing scope declarations can cause the skill to be invoked with broader-than-necessary capabilities or without meaningful operator review, increasing the risk of unintended file writes and external network access.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The invocation text is broad enough to match generic requests for news updates, engineering briefings, industry reports, or scheduled digests, which can cause the agent to select this skill in contexts the user did not specifically intend. Because the skill performs live network fetching and can be scheduled, overbroad routing increases the chance of unnecessary external requests and autonomous recurring actions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The description requires the skill to "generate one-sentence Chinese summaries for each article," which imposes a specific output language by default. The rest of the document consistently reinforces Chinese-only output without indicating user opt-in or an available language selection.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

These lines describe the digest as a "formatted Chinese digest" and "One-sentence Chinese summaries generated by LLM at render time," establishing a fixed locale requirement. Because no user choice is offered here, this conflicts with the policy against forcing a specific language without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The recommended flow explicitly instructs the calling LLM to "generate a one-sentence Chinese summary" for each article. This is another natural-language policy issue because it enforces a specific output language in the operational instructions rather than offering a configurable locale.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This manifest repeatedly sets source language to "en", beginning at L07, with no indication that users can choose another language or that the skill is intentionally limited to an English-only region or compliance context. Under the policy, a fixed language/locale requirement in natural-language configuration is a violation unless it is justified or optional.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The category mapping hard-codes Chinese display labels in the natural-language content, which implies the skill presents output in a specific language. There is no nearby indication of user opt-in, language selection, or a documented region-specific reason for enforcing Chinese labels.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This Python file contains natural-language instructions and status messages in Chinese, and later emits Chinese-only runtime output, but nowhere indicates that language selection is optional or configurable. Under the policy, forcing a specific language without user opt-in is a locale/language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code file includes natural-language instructions that require Chinese output, such as the module description saying it generates a one-line Chinese summary. The policy scope applies to all file types, and the file does not offer a language choice or explain a justified region-specific requirement.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The SUMMARY_HINT templates explicitly instruct the LLM to produce summaries in Chinese for every category. Because there is no opt-in, fallback, or locale selection, this is a natural-language locale policy violation rather than a code-security issue.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with only a lower bound, so builds may resolve to different versions over time. This weakens supply-chain integrity and makes it difficult to ensure that a known-safe feedparser release is consistently installed, especially given that the package has had prior advisories.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
feedparser>=6.0
beautifulsoup4>=4.12
requests>=2.28
python-dateutil>=2.8

Unverifiable Dependency: feedparser has 10 known advisory(ies) (CVE-2011-1157 (feedparser Cross-site Scripting vulnerability); CVE-2009-5065 (feedparser Cross-site Scripting vulnerability); CVE-2011-1158 (feedparser Cross-site Scripting vulnerability) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding

feedparser has known historical advisories, and because the manifest does not pin a version, it is impossible to verify from this file whether a patched or vulnerable release will be installed. In a skill that parses third-party feeds from many external sources, that uncertainty is more relevant because untrusted content is expected input.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

beautifulsoup4 is unpinned, which allows environment-dependent resolution to newer or unexpected releases. While not an immediate exploit by itself, it increases reproducibility and supply-chain risk because the installed code is not strictly controlled.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
feedparser>=6.0
beautifulsoup4>=4.12
requests>=2.28
python-dateutil>=2.8
ddgs>=7.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

requests is declared with a minimum version only, so deployments may pull different releases with different security properties. Because requests has a history of security advisories, failing to pin a vetted version leaves uncertainty about whether affected versions could be installed.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
feedparser>=6.0
beautifulsoup4>=4.12
requests>=2.28
python-dateutil>=2.8
ddgs>=7.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding

requests has multiple advisories and is not pinned, so the actual security posture of installations cannot be verified from the manifest. Since this skill fetches data from numerous external sites, using a known-safe requests release is important to avoid exposure to client-side parsing, redirect, or credential-handling issues fixed in later versions.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

python-dateutil is not version-pinned, which creates non-reproducible installations and weakens dependency governance. This is a low-severity supply-chain hygiene issue rather than a direct code execution flaw in the file itself.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
feedparser>=6.0
beautifulsoup4>=4.12
requests>=2.28
python-dateutil>=2.8
ddgs>=7.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

ddgs is also unpinned, allowing the resolved package version to drift over time. In a scraping/news aggregation skill that depends on external network content, predictable dependency versions are important to reduce supply-chain and operational risk.

Content

Scanner excerpt · requirements.txt (reported line 5)May include surrounding context.

text
beautifulsoup4>=4.12
requests>=2.28
python-dateutil>=2.8
ddgs>=7.0

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring and all user-facing CLI messages indicate the skill is designed to operate in Chinese only, with no visible option for users to select another language or locale. This is a natural-language policy concern because the file imposes a specific language without opt-in or documented justification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The docstring for format_digest says each news item will include a '一句话中文总结', implying the function outputs a Chinese one-sentence summary for every article. However, when zh_summary is missing, the implementation falls back to wrapping the original title in brackets and explicitly relies on an external LLM to generate the Chinese summary later, which contradicts the documented behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.