Back to skill

Security audit

Tageblatt Headlines

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent for archiving Tageblatt headlines, but its script can fetch arbitrary URLs and the documented cron/Telegram workflow adds recurring and external-sharing behavior that users should review first.

Review before installing. Use it only if you want a local Tageblatt headline archiver, avoid passing untrusted values to --url, and consider removing or restricting that option to https://www.tageblatt.de/. Enable the cron and Telegram workflow only after confirming the schedule, destination, and archive path are what you want.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_headlines.py:25
Finding

Unrestricted URL Fetching Enables SSRF and Local Resource Access

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch_headlines.py, lines 25–27, 61, and 89
Vulnerability Type: Server-Side Request Forgery (SSRF) and local resource access
Risk Level: Medium

Vulnerable Code

python
def fetch_html(url: str, timeout: int) -> str:
    with request.urlopen(url, timeout=timeout) as response:  # noqa: S310 (trusted URL)
        return response.read().decode("utf-8", errors="ignore")
python
parser.add_argument("--url", default=DEFAULT_URL, help="Ziel-URL (Standard: %(default)s)")
python
html_content = fetch_html(args.url, args.timeout)

Technical Analysis

The --url command-line argument accepts an arbitrary URL and passes it directly to urllib.request.urlopen. Contrary to the inline trusted URL comment, the value is not restricted to the declared https://www.tageblatt.de/ source.

No validation is applied to:

  • The URL scheme
  • The destination hostname
  • Redirect destinations
  • Embedded URL credentials
  • Resolved loopback, link-local, private, or reserved IP addresses

Consequently, an attacker who can control the script's arguments may direct the process to HTTP services on internal networks or localhost. Depending on the schemes supported by the runtime's URL handlers, local resources such as file: URLs may also be accessed.

The fetched content is processed by extract_headlines. Content matching the expected heading pattern can then be printed to standard output and written to an attacker-selected output path. This makes response-data extraction possible when the targeted resource contains, or can be made to return, matching markup.

Attack Path

  1. The attacker gains the ability to influence arguments supplied to fetch_headlines.py, directly or through an automation workflow that incorporates untrusted input.
  2. The attacker supplies a crafted --url targeting a loopback service, private-network endpoint, cloud metadata-like endpoint, or supported local-resource U ...[truncated 1219 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the --url option if alternate sources are not a required feature, and always use the fixed DEFAULT_URL.
  2. If configurability is required, parse URLs with urllib.parse.urlsplit and enforce:
    • The https scheme only
    • An exact allowlist such as www.tageblatt.de
    • No embedded username or password
    • An expected port, normally 443
  3. Resolve the hostname and reject loopback, private, link-local, multicast, unspecified, and reserved addresses using Python's ipaddress module.
  4. Disable automatic redirects or validate every redirect destination with the same scheme, host, and resolved-address policy.
  5. Reject non-HTTP schemes explicitly, including file, ftp, and data.
  6. Apply response-size limits before reading the complete body to reduce denial-of-service risk.
  7. Replace the misleading # noqa: S310 (trusted URL) suppression with validation that establishes the trust boundary before urlopen is called.
  8. Add security tests covering localhost URLs, private IP addresses, alternative schemes, URL credentials, DNS resolution to private addresses, and redirects to prohibited destinations.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (6)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill performs network access and file writes but does not declare any explicit tool scope or permissions boundary. That makes its operational capabilities less transparent to the orchestrator and reviewers, increasing the chance of unintended invocation or over-privileged execution.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The description includes broad trigger phrases like saving locally and automated workflows, which can cause the skill to match routine user requests without clearly signaling that it will fetch remote content and persist data. Over-broad activation increases the risk of accidental execution of networked and state-changing behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill instructs automated forwarding of downloaded content via Telegram without prominently warning that data will be transmitted to an external service. Even though headlines are likely public, silent outbound transmission is risky because it normalizes exfiltration behavior and could be repurposed or triggered without informed user consent.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

request.urlopen is used on a caller-supplied URL without any host restrictions, making the script an arbitrary HTTP client rather than a fixed-source headline fetcher. In a local agent or automation environment, this can enable SSRF-style behavior, service probing, or data access from networks reachable by the agent but not by the requester.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill is described as a source-specific archiver for tageblatt.de, but exposing a user-controlled --url option allows the script to fetch arbitrary destinations instead. In an agent context, this broadens the network capability beyond the declared purpose and can be abused for unintended outbound requests, including access to internal or sensitive network endpoints if the runtime has such reach.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file’s natural-language strings and help text are entirely in German, including the module docstring and argparse descriptions, which imposes a specific language on users without any opt-in or language-selection mechanism. This matches the policy category for locale/language constraints because the script does not indicate that it is intentionally region-specific beyond targeting one website.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.