Back to skill

Security audit

Danish News Feeds

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a Danish RSS aggregator rather than malware, but its documentation overstates its behavior and the code has feed-integrity weaknesses users should review before installing.

Review this skill before installing or publishing its feeds. Prefer a fixed version that keeps TLS verification enabled, removes plaintext HTTP feeds or marks them untrusted, serializes XML with a safe library, pins dependencies, and aligns the README with what the scripts actually do. Only add the cron job if you intentionally want scheduled background refreshes.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
aggregate_feeds.py:58
Finding

TLS certificate validation is explicitly disabled for remote feed retrieval

Content
View full analysis

Vulnerability Details

File Location: aggregate_feeds.py, lines 58-69
Vulnerability Type: Improper certificate validation (CWE-295)
Risk Level: High

Vulnerable Code

python
try:
    # Create SSL context that doesn't verify certificates (for testing)
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    
    req = urllib.request.Request(
        url,
        headers={"User-Agent": USER_AGENT}
    )
    
    with urllib.request.urlopen(req, timeout=30, context=ctx) as response:
        content = response.read().decode("utf-8")

Technical Analysis

The aggregator deliberately disables both TLS certificate validation and hostname verification for every configured HTTPS feed. Consequently, HTTPS provides encryption without authenticating the remote server.

Any party capable of intercepting network traffic can present an arbitrary certificate and impersonate a configured news provider. The resulting attacker-controlled response is parsed as RSS or Atom and incorporated into combined_danish_news.xml.

Disabling verification globally is unnecessary for the Skill's declared RSS aggregation functionality. Python's default SSL context already validates certificates using the host trust store.

Attack Path

  1. A victim runs aggregate_feeds.py on an untrusted or compromised network.
  2. An attacker intercepts a request to a configured HTTPS RSS endpoint through a malicious access point, DNS manipulation, proxy compromise, or upstream routing attack.
  3. The attacker presents any TLS certificate.
  4. Because hostname and certificate verification are disabled, the client accepts the certificate.
  5. The attacker returns a crafted RSS or Atom document containing false headlines, attacker-controlled links, or oversized content.
  6. The content is incorporated into the generated RSS file and subsequently delivered to consumers.

...[truncated 426 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove the custom verification-disabling settings and use the default verified context:

    python
    ctx = ssl.create_default_context()
    with urllib.request.urlopen(req, timeout=30, context=ctx) as response:
        content = response.read(MAX_RESPONSE_BYTES + 1)
    
  • Reject content exceeding a defined response-size limit.

  • Validate the response Content-Type and final URL after redirects.

  • Permit only HTTPS URLs from an explicit hostname allowlist.

  • If a specific provider requires a private CA, install or configure that CA explicitly rather than disabling validation globally.

  • Record certificate and parsing failures without falling back to insecure transport.

T09 · Insecure Skill Coding Practices

Warning
Location
aggregator.py:44
Finding

A feed is retrieved over unauthenticated plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: aggregator.py, line 44
Additional Location: feeds.json, line 23
Vulnerability Type: Cleartext transmission of externally sourced data (CWE-319)
Risk Level: Medium

Vulnerable Code

python
"sports": [
    {"url": "https://www.tv2.dk/sport/rss", "name": "TV2 Sport", "authority": 8},
    {"url": "http://www.bold.dk/feed/rss_by_tag/246752", "name": "Bold.dk", "authority": 7},
    {"url": "https://www.tipsbladet.dk/rss-feed-fra-tips-bladet", "name": "Tipsbladet", "authority": 7},

The same endpoint is present in the secondary configuration:

json
{"name": "Bold.dk", "url": "http://www.bold.dk/feed/rss_by_tag/246752", "category": "sports"}

Technical Analysis

The Bold.dk feed is fetched over plaintext HTTP. HTTP provides neither server authentication nor transport integrity. A network-positioned attacker can therefore modify the feed response even if all HTTPS validation issues elsewhere are corrected.

The fetched title, link, description, and publication data are treated as source content and published in the output feed. The configured authority value can also cause injected entries to receive favorable placement.

Attack Path

  1. The aggregator requests the Bold.dk feed through plaintext HTTP.
  2. A network-positioned attacker intercepts or alters the response.
  3. The attacker supplies forged feed entries with misleading titles and attacker-controlled links.
  4. The aggregator accepts and ranks those entries as content from Bold.dk.
  5. Users consuming the generated feed may follow the malicious links or trust the forged attribution.

Impact Assessment

The attacker gains control over content attributed to the affected source, enabling misinformation, phishing, traffic redirection, and delivery of malicious links to downstream users. This does not itself grant local system privileges, but it compromises the integrity and aut ...[truncated 40 chars]

Remediation
View remediation

Remediation Suggestions

  • Replace the endpoint with an HTTPS equivalent verified to be operated by the intended provider.
  • If no authenticated HTTPS endpoint exists, remove the source or explicitly treat it as untrusted.
  • Enforce an https URL scheme for every configured feed.
  • Validate redirect destinations so an HTTPS URL cannot redirect to HTTP.
  • Consider signing or independently validating high-trust source data if source attribution is security-sensitive.

T09 · Insecure Skill Coding Practices

Warning
Location
aggregator.py:136
Finding

Untrusted feed fields are interpolated directly into generated XML

Content
View full analysis

Vulnerability Details

File Location: aggregator.py, lines 136-149
Vulnerability Type: Improper neutralization of data in XML output (CWE-91)
Risk Level: Medium

Vulnerable Code

python
items = ""
for entry in entries[:CONFIG["max_items_per_feed"]]:
    items += f"""<item>
    <title><![CDATA[{entry['title']}]]></title>
    <link>{entry['link']}</link>
    <description><![CDATA[{entry['summary']}]]></description>
    <pubDate>{entry['published']}</pubDate>
    <source>{entry['source']}</source>
    <category>{feed_title}</category>
</item>

"""

Technical Analysis

Remote feed fields are inserted into XML through string interpolation without XML-safe serialization.

The link, published, and other non-CDATA values are not escaped. Characters such as & and < can corrupt the document or introduce attacker-selected XML elements. Although the title and summary use CDATA sections, an attacker can include the CDATA terminator ]]> and append arbitrary XML markup after it.

Because feed content is remotely supplied—and can also be modified through the transport weaknesses identified above—the generated values must be treated as untrusted. Building XML with an XML library would automatically escape text nodes and prevent structural injection.

Attack Path

  1. An attacker controls or intercepts one of the configured feed responses.
  2. The attacker supplies a title such as a value containing ]]> followed by attacker-selected XML, or supplies a link containing raw XML metacharacters.
  3. fetch_feed() stores the value without structural validation.
  4. generate_rss() interpolates it directly into the RSS document.
  5. The resulting file is malformed or contains attacker-injected elements.
  6. A downstream RSS reader or web application processes the manipulated output. If that consumer unsafely renders feed markup, the issue can contribute to content spoofing or client-side i ...[truncated 409 chars]
Remediation
View remediation

Remediation Suggestions

  • Stop constructing XML through string interpolation.
  • Generate all channel and item fields with xml.etree.ElementTree, lxml, or another maintained XML serializer.
  • Assign untrusted content only through element .text properties so the serializer escapes it.
  • Validate links and permit only expected schemes such as https.
  • Normalize publication dates to a valid RSS date representation.
  • Add tests containing &, <, >, quotes, and ]]> in every remotely sourced field.
  • Serve generated feeds with an appropriate XML content type and ensure downstream web renderers apply independent output encoding.

T08 · Insecure Dependencies

Note
Location
SKILL.md:24
Finding

Installation instructions use unpinned third-party dependencies

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 24-27
Vulnerability Type: Uncontrolled dependency version resolution (CWE-1104)
Risk Level: Low

Vulnerable Code

bash
# Install dependencies
pip install feedparser python-dateutil

Technical Analysis

The installation command resolves the newest versions available from the user's configured Python package index at installation time. The reviewed Skill therefore does not define the exact dependency code that will execute.

The package names are established dependencies and the audit found no evidence that they are malicious. Nevertheless, unpinned installation makes builds non-reproducible and exposes users to newly compromised or defective releases, a compromised configured package index, and dependency-resolution changes after the Skill has been reviewed.

Attack Path

  1. A user follows the documented installation command.
  2. pip queries the user's configured index and resolves currently available package versions and transitive dependencies.
  3. A compromised package release, compromised index, or maliciously altered local index configuration supplies unsafe package code.
  4. Package installation or later import executes code that was not part of the audited artifact.

This is a supply-chain exposure rather than evidence of an existing malicious dependency.

Impact Assessment

Python package installation can execute build backend logic under the privileges of the user running pip. A compromised dependency could consequently read or modify that user's files, access available credentials, or execute arbitrary commands. The actual impact depends on the installation environment and whether the command is run with elevated privileges.

Remediation
View remediation

Remediation Suggestions

  • Provide a lock file or requirements file containing reviewed, exact versions.
  • Use hashes with pip install --require-hashes -r requirements.txt.
  • Pin and review transitive dependencies as well as direct dependencies.
  • Install into a dedicated virtual environment as an unprivileged user.
  • Avoid sudo pip install.
  • Use a trusted package index and periodically update pins through a controlled dependency-review process.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • 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)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code broadly matches the high-level theme of a Danish news RSS aggregator, but the declared description materially overstates and misrepresents the implemented behavior. The script fetches feeds, parses RSS/Atom, sorts by date, and emits a single file named combined_danish_news.xml. It does not generate the six named feed variants, does not implement category curation, does not auto-refresh on a schedule, and does not deduplicate or rank by authority. The description therefore does not accurately represent the supplied code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The code largely matches the general purpose of aggregating Danish news RSS feeds into category-based outputs, including deduplication and authority/time-based sorting. However, several material claims in the description are not implemented. Most notably, the code does not aggregate 100+ feeds; it uses a substantially smaller hardcoded feed list. It also does not auto-refresh every 15 minutes—although a 900-second refresh interval appears in config, there is no loop, scheduler, or trigger using it. The 'danish-all.xml (top 30 sources)' claim is also not reflected in behavior, since the script simply merges all category entries rather than selecting top 30 sources. There are no obvious undeclared malicious or unrelated capabilities, but the description overstates and misstates key behavior enough to qualify as a mismatch.

Content

No source excerpt is available for this finding.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · SKILL.md (reported line 84)May include surrounding context.

  • ✅ Source authority ranking (DR > major newspapers > regional)
  • ✅ Time filtering (last 24h by default)
  • ✅ RSS 2.0 compliant
  • ✅ UTF-8 encoding
  • ✅ Auto-refresh (15 min interval)
  • ✅ Media RSS extensions for images

Hosting

Self-Host (Docker)

bash
docker build -t danish-news-aggregator .
docker run -d -p 8080:8080 danish-news-aggregator

Cron Job

bash
# Add to crontab
*/15 * * * * cd /path/to/aggregator && python3 aggregator.py

Subscribe

Add these URLs to your RSS reader:

Credits

Aggregates from: DR, Berlingske, Politiken, Information, Nordjyske, Fyens, JydskeVestkysten, Bold.dk, Tipsbladet, TV2 Sport, Finans, Nationalbanken, Vers

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code disables TLS certificate and hostname verification for all feed fetches, which makes HTTPS connections vulnerable to man-in-the-middle interception and content tampering. In this skill's context, untrusted network or upstream actors could inject malicious or misleading feed content into the generated RSS output, undermining integrity and potentially exposing downstream consumers to phishing or malicious links.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill documents executable behavior involving network access, local file reads, and file writes, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an avoidable trust gap: a host may grant broader capabilities than intended, and reviewers cannot easily verify least-privilege expectations from the manifest alone.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
78% confidence
Finding

The Docker guidance uses an unpinned local image reference at runtime, which reduces build and deployment reproducibility and makes it easier to run an unexpected image variant if tags are later changed or rebuilt. While this is not an immediate exploit by itself, supply-chain ambiguity increases risk in operational environments.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest describes six output feeds, category-specific aggregation, deduplication, and ranking by source authority. This file defines a single output file and only fetches feeds, concatenates articles, sorts them by parsed publication date, and writes one combined RSS file, with no category partitioning, deduplication, or authority-based ranking logic.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code sets the generated RSS channel language to "da" and the skill branding/instructions throughout the file present it as a Danish-only aggregator. Under the policy, forcing a specific language or locale without user opt-in can be a natural-language policy violation unless the restriction is clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest describes a comprehensive aggregator covering 100+ feeds and producing an 'all' feed from the top 30 sources. In code, the FEEDS constant contains only a few dozen entries across categories, and the generated all-feed is built only from that limited hardcoded set, so the implemented scope is materially narrower than claimed.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code hard-codes the RSS tag to "da" for every generated feed. Because the same generator is used for the English-language feed, the skill imposes a locale setting that does not reflect user choice and is inconsistent with the content, which matches the policy's language/locale violation criterion.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code combines all category entries and sorts them by authority and time, then truncates items per feed, but it never selects or limits aggregation to a top 30 set of sources. Ranking entries is not the same as choosing the top 30 sources, so the behavior does not match the manifest's claimed feed construction.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest says the skill produces curated feeds that deduplicate items and focus on Danish news categories, but this output includes the same story repeated across multiple outlets (L646-L658) and the same election-test item repeated across several outlets (L660-L682). The feed also includes older evergreen/lifestyle explainer content such as 2020 and 2022 articles (L751-L771), which does not align well with a current-news aggregator claiming ranked, refreshed Danish news feeds.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest says the skill combines 100+ Danish RSS feeds into 6 curated unified feeds focused on specific news categories, but this file documents only 80+ feeds and includes additional categories outside that scope such as politics, universities, podcasts, radio, weather, tourism, and international coverage. This indicates the skill’s documented source set is materially different from the manifest’s stated scope and output model.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
99% confidence
Finding

The manifest enumerates six feeds, but the list in code includes seven filenames: danish-all.xml, danish-national.xml, danish-regional.xml, danish-sports.xml, danish-business.xml, danish-tech.xml, and danish-english.xml. This is a direct mismatch between the declared outputs and the actual generated artifacts.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The RSS channel declares a fixed language value of "da", which imposes a specific locale at the feed level. Under the stated policy, forcing a language or locale without user opt-in can be a natural-language policy violation unless the constraint is explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The title and description position the resource as specifically Danish, and the file largely enumerates Danish-language sources without any user opt-in or explanation of why this locale restriction is required. Under the stated policy, locale-specific constraints should either be optional for the user or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The manifest names and describes the skill specifically as a Danish news aggregator, which implies a fixed language/locale focus. Under the policy, locale constraints should either be user-selectable or clearly justified as region-specific; this file does not explicitly provide either.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The file description states 'Comprehensive Danish RSS feed aggregator,' which implies a Danish news-focused aggregator consistent with the skill manifest. However, the configured feeds include weather and broader topic-specific categories not mentioned in the documented outputs, creating a mild documentation-to-content divergence.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes six curated feeds focused on national, regional, sports, business, tech, and English-language Denmark, plus an all-feed. This file includes additional categories such as domestic, foreign, politics, and weather that are not reflected in that stated output scope, indicating the configured content set is broader than the described behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.