Back to skill

Security audit

news-agent-skills

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent news API helper, but it ships a reusable development bearer token and state-changing task triggers without enough host, transport, or confirmation controls.

Install only for a trusted local or test News Agent backend. Do not point NEWS_API_BASE_URL at an untrusted or plaintext remote service, and treat crawl/analyze/trend commands as state-changing backend operations that may consume resources. The publisher should replace the fixed development token with user-provided scoped auth, enforce HTTPS or loopback-only development use, validate the API host before sending credentials, and require confirmation for POST task triggers.

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

Error
Location
scripts/get_articles.py:8
Finding

Hard-Coded Development Authentication Bypass Credential

Content
View full analysis

Vulnerability Details

File Location: scripts/get_articles.py:8-9; duplicated in scripts/get_dashboard.py:8-9, scripts/get_trends.py:8-9, and scripts/trigger_task.py:8-9; bypass behavior documented in SKILL.md:178 and references/api_docs.md:17-21
Vulnerability Type: Hard-coded authentication bypass credential
Risk Level: High

Vulnerable Code

The following complete configuration segment appears in each affected Python script:

python
BASE_URL = os.getenv("NEWS_API_BASE_URL", "http://localhost:8030/api/v1")
HEADERS = {"Authorization": "Bearer PharmaBlock Gateway"}

The API documentation confirms that the fixed value enables development authentication:

http
Authorization: Bearer PharmaBlock Gateway

It further states that the gateway detects this token and injects simulated user information.

Technical Analysis

All four scripts unconditionally attach a publicly documented, fixed bearer credential to API requests. This credential is not a unique user secret and, according to the included documentation, causes the gateway to inject a simulated identity, bypassing the normal production SSO flow.

The affected operations include read-only access to articles, dashboard data, trends, and task status, as well as state-changing requests that trigger crawling, analysis, and trend-processing jobs. If a reachable deployment retains support for this development token, anyone who knows the value can reproduce the authorization header without possessing a legitimate SSO session.

The risk is compounded by NEWS_API_BASE_URL being configurable and by the default URL using plaintext HTTP. The scripts will send the bearer value to whichever origin is configured, without validating that it is a trusted host or requiring TLS. A maliciously configured endpoint or a network observer on an unencrypted route could therefore capture the token.

The repository does not contain the gateway implementat ...[truncated 2053 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the fixed Bearer PharmaBlock Gateway value from all distributed scripts and documentation.
  2. Require authentication material to be supplied at runtime through a protected mechanism, such as a secret environment variable, operating-system credential store, or normal SSO session.
  3. Do not provide a universal development token. Use short-lived, uniquely issued credentials with narrowly scoped permissions where automated access is required.
  4. Disable development authentication bypasses by default. If one is indispensable, compile or activate it only in an explicitly isolated local-development profile.
  5. Enforce a startup failure when a development bypass is enabled outside loopback-only environments.
  6. Require HTTPS for every non-loopback API URL and reject plaintext remote endpoints.
  7. Validate NEWS_API_BASE_URL against an approved origin list before attaching credentials, preventing credential transmission to arbitrary hosts.
  8. Apply server-side authorization independently to each endpoint, especially the state-changing task routes.
  9. Rotate or permanently invalidate the documented token in every existing deployment.
  10. Add rate limits, task deduplication, concurrency controls, and audit logging to task-trigger endpoints to reduce workload abuse.
  11. Add automated security tests confirming that production configurations reject the historical development token and unauthenticated requests.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (21)

Tainted flow: 'BASE_URL' from os.getenv (line 8, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
91% confidence
Finding

The request target is built from NEWS_API_BASE_URL, an environment-controlled value, and the script automatically sends an Authorization header to that destination. If an attacker can influence the environment or deployment configuration, they can redirect requests to an attacker-controlled host and capture the bearer token or use the script for SSRF-style access to internal services.

Content

Scanner excerpt · scripts/get_articles.py (reported line 24)May include surrounding context.

python
if end_date:
        params["end_date"] = end_date

    resp = requests.get(f"{BASE_URL}/articles", headers=HEADERS, params=params, timeout=30)
    resp.raise_for_status()
    return resp.json()

Tainted flow: 'BASE_URL' from os.getenv (line 8, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The request URL is derived from an environment variable and the code always attaches a static Authorization header, so if NEWS_API_BASE_URL is changed to an attacker-controlled host the bearer token will be sent to that host. Because the default scheme is also plain HTTP, this can additionally expose the token and dashboard data to interception or redirection in transit.

Content

Scanner excerpt · scripts/get_dashboard.py (reported line 13)May include surrounding context.

python
def get_dashboard():
    resp = requests.get(f"{BASE_URL}/dashboard", headers=HEADERS, timeout=30)
    resp.raise_for_status()
    return resp.json()

Tainted flow: 'BASE_URL' from os.getenv (line 8, credential/environment) → requests.get (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/get_trends.py (reported line 13)May include surrounding context.

python
def get_hot(days=7, top_n=20):
    resp = requests.get(f"{BASE_URL}/trends/hot", headers=HEADERS,
                        params={"days": days, "top_n": top_n}, timeout=30)
    resp.raise_for_status()
    return resp.json()

Tainted flow: 'BASE_URL' from os.getenv (line 8, credential/environment) → requests.get (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/get_trends.py (reported line 20)May include surrounding context.

python
def get_keyword(keyword, days=30):
    resp = requests.get(f"{BASE_URL}/trends/keyword", headers=HEADERS,
                        params={"keyword": keyword, "days": days}, timeout=30)
    resp.raise_for_status()
    return resp.json()

Tainted flow: 'BASE_URL' from os.getenv (line 8, credential/environment) → requests.get (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/get_trends.py (reported line 27)May include surrounding context.

python
def get_category(days=30):
    resp = requests.get(f"{BASE_URL}/trends/category", headers=HEADERS,
                        params={"days": days}, timeout=30)
    resp.raise_for_status()
    return resp.json()

Tainted flow: 'url' from os.getenv (line 26, credential/environment) → requests.post (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/trigger_task.py (reported line 29)May include surrounding context.

python
url = f"{BASE_URL}{path}"

    if method == "POST":
        resp = requests.post(url, headers=HEADERS, timeout=30)
    else:
        resp = requests.get(url, headers=HEADERS, timeout=30)

Tainted flow: 'url' from os.getenv (line 26, credential/environment) → requests.get (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/trigger_task.py (reported line 31)May include surrounding context.

python
if method == "POST":
        resp = requests.post(url, headers=HEADERS, timeout=30)
    else:
        resp = requests.get(url, headers=HEADERS, timeout=30)

    resp.raise_for_status()
    return resp.json(), label

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documents use of environment variables and HTTP API access but does not declare any explicit tool scope or permission boundary. This creates a mismatch between the skill's effective capabilities and its stated trust model, increasing the risk that an agent may invoke networked actions or consume sensitive environment configuration without clear operator awareness.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill presents commands that trigger crawl, analyze, and trend tasks, but it does not clearly warn that these are backend state-changing operations. In an agent setting, that omission can cause unintended job execution, resource consumption, data modification, or downstream processing without the user's informed consent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The description is entirely in Chinese, which implies a fixed language/locale experience, but there is no indication that users can opt into this language or that the skill is intentionally region-specific. Under the language/locale policy, forcing a specific language without user choice or clear justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation exposes task-triggering endpoints for crawl, analyze, and trend jobs without any warning that they cause state changes or resource-consuming background work. In an agent skill context, this increases the chance an automated system will invoke them as if they were harmless reads, leading to unintended job execution, denial-of-service against backend workers, or unauthorized operational changes if access controls are weak.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script's docstring, argument descriptions, status messages, and formatted output are all fixed in Chinese. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The module docstring, argument descriptions, status messages, and formatted output are all hard-coded in Chinese, with no indication that the user can choose another language or that the tool is intentionally limited to a Chinese-only audience. This creates a locale/language policy concern because the skill imposes a specific language by default.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

All natural-language strings in the script, including the description, help text, and output messages, are fixed to Chinese. This can violate language/locale policy when the skill does not provide user opt-in, a language selection mechanism, or justification for being Chinese-only.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file’s docstring, CLI description, help text, and status/output messages are all written only in Chinese. This imposes a specific language on users without opt-in or any indication that the skill is intentionally limited to a Chinese-speaking context, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest description and all user-facing instructions are written in Chinese, and no opt-in or alternative language is offered. Under the stated policy, forcing a specific language without user choice can be a natural-language policy violation unless the locale restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This manifest file describes broad capabilities and use cases such as querying news, triggering collection/analysis tasks, and trend analysis, but it does not define any specific invocation phrases, boundaries, or exclusion conditions. In a manifest context, that lack of specificity can make activation intent ambiguous and increase the chance of unintended invocation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The documentation is entirely in Chinese and does not indicate any language choice or locale scope. Under the language/locale policy, forcing a single language without opt-in can be a natural-language policy violation unless the regional constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

This code performs an HTTP GET to an external API and includes user-provided filters such as keyword and date range in the request parameters. While the script has an error message on failure, it does not provide any confirmation, informational notice, or comment/docstring disclosing that user input will be sent over the network.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code performs a network request to an API endpoint and includes an Authorization header, but the file provides no explicit warning or disclosure to the user that data will be sent over the network. Although the script prints errors, it does not communicate the outbound API access in a docstring, comment, or prompt near the request itself.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The script sends the user-provided keyword to a remote API without clearly notifying the user at the point of use that their query leaves the local environment. In a news-analysis context, keywords may reveal research interests or sensitive investigation topics, so undisclosed transmission creates a privacy and data-handling concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.