Back to skill

Security audit

Miniflux News

Security checks for vulnerabilities and agentic risk

Overview

This Miniflux skill is mostly coherent, but it handles API tokens in ways that could expose them if configured or used unsafely.

Install only if you are comfortable granting this skill access to your Miniflux account. Use an HTTPS Miniflux URL, prefer a limited-purpose token, avoid passing real tokens on the command line, and be aware that explicit mark-read commands can change feed state.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/miniflux.py:75
Finding

Miniflux API Token Can Be Transmitted over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/miniflux.py:75-93
Vulnerability Type: Missing transport security enforcement for credential-bearing requests
Risk Level: High

Vulnerable Code:

python
def _request(path: str, query: dict | None = None, *, method: str = "GET", body: dict | None = None):
    base = _require("MINIFLUX_URL", "MINIFLUX_URL", "url").rstrip("/")
    token = _require("MINIFLUX_TOKEN", "MINIFLUX_TOKEN", "token").strip()

    url = base + path
    if query:
        url = url + "?" + urllib.parse.urlencode({k: v for k, v in query.items() if v is not None})

    data_bytes = None
    if body is not None:
        data_bytes = json.dumps(body).encode("utf-8")

    req = urllib.request.Request(url, data=data_bytes, method=method)
    req.add_header("X-Auth-Token", token)
    req.add_header("Accept", "application/json")
    if data_bytes is not None:
        req.add_header("Content-Type", "application/json")

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = resp.read()

Technical Analysis

The Miniflux base URL is read from user-controlled configuration or the MINIFLUX_URL environment variable and used without validating its URL scheme. The code then places the Miniflux API token in the X-Auth-Token request header.

Although the documentation uses HTTPS in its examples, the implementation accepts an http:// URL. When HTTP is used, neither the authentication header nor the response is protected by TLS. A network observer or active man-in-the-middle attacker can therefore capture the token and inspect or alter Miniflux API traffic.

Sending the token to the configured Miniflux API is necessary for the declared functionality. The security issue is not the network operation itself, but the absence of enforcement ensuring that the credential is transmitted through a secure transport.

Attack Path

  1. The victim conf ...[truncated 1178 chars]
Remediation
View remediation

Remediation Suggestions

  • Parse the configured base URL with urllib.parse.urlparse() before constructing a request.
  • Reject every scheme except https by default.
  • If plaintext HTTP is required for local development, permit it only for loopback destinations such as 127.0.0.1, ::1, or localhost, and only behind an explicit option such as --allow-insecure-http.
  • Reject URLs containing embedded credentials or unexpected components.
  • Ensure authentication headers are not forwarded to a different origin during redirects. Prefer disabling redirects for authenticated API calls or validating that every redirect retains the original HTTPS scheme, hostname, and port.
  • Update SKILL.md to state that HTTPS is mandatory rather than merely showing HTTPS in examples.
  • Use a dedicated Miniflux token with only the minimum permissions needed by the intended commands, and rotate any token suspected of having been transmitted over HTTP.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:30
Finding

API Token Is Accepted and Documented as a Command-Line Argument

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:30-33; supporting implementation at scripts/miniflux.py:332-335
Vulnerability Type: Secret exposure through process arguments and shell history
Risk Level: Medium

Vulnerable Documentation:

bash
python3 skills/miniflux-news/scripts/miniflux.py configure \
  --url "https://your-miniflux.example" \
  --token "<api-token>"

Supporting Implementation:

python
p_cfg = sub.add_parser("configure", help="Write/update config file")
p_cfg.add_argument("--url", help="Miniflux base URL, e.g. https://reader.example.com")
p_cfg.add_argument("--token", help="Miniflux API token")
p_cfg.set_defaults(func=cmd_configure)

Technical Analysis

The recommended configuration procedure places the Miniflux API token directly in a command-line argument. Command-line secrets can be retained in shell history and may be visible in process inspection interfaces while the command is executing. They can also be collected by terminal logging, process-monitoring software, command auditing, or diagnostic tooling.

The configuration file is ultimately given restrictive permissions, but that protection does not address exposure before the token is written to the file. Accepting a secret through an ordinary command-line option is unnecessary because the token can be read through a non-echoing interactive prompt or standard input.

Attack Path

  1. The victim follows the setup command documented in SKILL.md and supplies a real token through --token.
  2. The shell may save the complete command, including the token, in its history.
  3. During execution, the token may also be visible to local process-inspection or monitoring facilities.
  4. A local user, support tool, log collector, or later reader of the shell history obtains the token.
  5. The party possessing the token authenticates directly to the configured Miniflux API.

Impact Assessment

T ...[truncated 608 chars]

Remediation
View remediation

Remediation Suggestions

  • Replace the recommended --token workflow with a non-echoing prompt implemented using getpass.getpass().
  • Alternatively, accept the token from standard input or from a user-selected file with restrictive permissions.
  • Avoid placing tokens in shell examples, process arguments, logs, exception messages, or diagnostic output.
  • Retain environment-variable support only where operationally necessary, because environment variables may also be exposed by some process and debugging environments.
  • Create the destination configuration file with mode 0600 at creation time rather than relying only on a best-effort chmod after writing.
  • Clarify the minimum token permissions. If mark-as-read functionality is needed, document that state-modification access is required; otherwise, recommend a separate read-only token and disable mutation commands.
  • Advise users who previously passed tokens on the command line to clear affected shell history securely and rotate the exposed tokens.
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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 (6)

Tainted flow: 'req' from os.environ.get (line 86, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/miniflux.py (reported line 93)May include surrounding context.

python
req.add_header("Content-Type", "application/json")

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = resp.read()
    except urllib.error.HTTPError as e:
        err_body = e.read().decode("utf-8", errors="replace")

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description frames the skill as read-oriented news fetching and summarization, but the documented behavior also includes mutating actions like marking entries read and writing/updating credential configuration. This mismatch can mislead operators or automated policy systems into approving a skill believed to be read-only when it can alter user state and local secrets.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill invokes a bundled Python script that uses network, shell, environment variables, and local file read/write, yet the manifest does not declare any tool scope or permission boundaries. This creates an overprivileged, opaque execution surface where an agent may use sensitive capabilities without explicit review, increasing the chance of credential exposure or unintended state changes.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
# Miniflux News

Use the bundled script to fetch entries, then format a clean list and optionally write summaries.

## Setup (credentials)

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill description emphasizes fetching and triaging unread items, but the script also exposes state-changing operations that mark entries or whole categories as read. In an agent setting, this expands capability beyond passive retrieval and can cause unintended data modification, especially if a higher-level orchestrator assumes the skill is read-only based on the manifest description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The bundled configure command stores the API token on disk in a local JSON file, but this credential persistence is not clearly disclosed in the skill metadata. While the code attempts restrictive permissions, undisclosed secret storage is relevant in a security review because users or agents may invoke configure without realizing credentials will be written to persistent storage.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.