Back to skill

Security audit

Daily Business Report

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its reporting purpose, but it needs review because it stores and prints a configured NewsData API key in plaintext.

Review before installing if you plan to use NewsData.io or scheduled sharing. Avoid passing real API keys until the skill redacts secrets from output and stores them with stronger protections; also verify cron recipients because generated reports can include local disk/RAM status.

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/report.py:27
Finding
NewsData API Key Is Stored and Exposed in Plaintext<![CDATA[ ## Vulnerability Details **File Location**: `scripts/report.py:27-34`, `scripts/report.py:108-112`, and `scripts/report.py:331-350` **Vulnerability Type**: Plaintext secret storage and disclosure **Risk Level**: Medium ### Vulnerable Code ```python def load_config() -> dict: if CONFIG_FILE.exists(): cfg = json.loads(CONFIG_FILE.read_text()) merged = {**DEFAULT_CONFIG, **cfg} return merged return DEFAULT_CONFIG.copy() def save_config(cfg: dict): CONFIG_DIR.mkdir(parents=True, exist_ok=True) CONFIG_FILE.write_text(json.dumps(cfg, indent=2)) ``` ```python def fetch_news(country: str = "us", api_key: str = "") -> dict: """News headlines. Uses NewsData.io if API key provided, else a fallback.""" if api_key: data = api_get(f"https://newsdata.io/api/1/latest?apikey={api_key}&country={country}&language=en&size=5") ``` ```python def cmd_config(city=None, crypto=None, news_country=None, news_key=None, show=False): cfg = load_config() if show: print(json.dumps(cfg, indent=2)) return if city: cfg["city"] = city if crypto: cfg["crypto"] = [c.strip().lower() for c in crypto.split(",")] if news_country: cfg["news_country"] = news_country if news_key: cfg["news_api_key"] = news_key save_config(cfg) print("Configuration updated.") print(json.dumps(cfg, indent=2)) ``` ### Technical Analysis The user-supplied NewsData API key is stored directly in the JSON configuration file under `~/.daily-report/config.json`. The code does not explicitly enforce restrictive permissions on either the configuration directory or file, so effective access depends on the user's environment and process umask. The full configuration is also printed by `config --show` and after every configuration update. Because the configuration includes `news_api_key`, the credential can be exposed through terminal history capture, CI/CD logs, scheduled-job ...[truncated 2214 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Avoid storing the API key in the regular preferences file.** - Read it from a dedicated environment variable such as `NEWSDATA_API_KEY`. - For interactive installations, use an operating-system credential store or secrets manager. 2. **Enforce restrictive permissions if file storage must remain supported.** - Create the configuration directory with mode `0700`. - Create or replace the secret-bearing file with mode `0600`. - Verify and repair existing permissions before reading the credential. - Use an atomic write procedure that preserves restrictive permissions. 3. **Redact secrets from all output.** - Replace `news_api_key` with a value such as `"***REDACTED***"` in `config --show`. - Do not print the full configuration after an update. - Display only the names of changed non-secret settings or indicate that a key is configured. 4. **Improve transport-level secret handling.** - Prefer a provider-supported authorization header instead of a URL query parameter. - If NewsData requires a query parameter, ensure request URLs are never written to application logs, exceptions, tracing systems, or telemetry. - Keep HTTPS certificate verification enabled. 5. **Support credential rotation.** - Document how users can revoke and replace a potentially exposed NewsData key. - Recommend rotating any key that has already appeared in shared terminal, CI, or cron logs. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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 (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented purpose does not accurately match behavior: it claims calendar aggregation but does not provide it, introduces an undeclared quote source, and performs local file writes without declaring them. Description-behavior mismatches undermine informed consent and security review because users and orchestrators may approve a skill for one purpose while it silently performs additional actions.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises no explicit tool scope or permissions while its documented behavior implies network access, reading local system state, writing configuration, and optionally writing report files. This weakens least-privilege boundaries and can cause the agent to invoke broader capabilities than users expect, increasing the risk of unintended data access or exfiltration.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The skill description includes broad trigger phrases such as daily report, morning briefing, business summary, or status dashboard, which can cause overly eager invocation in unrelated contexts. Accidental invocation matters here because the skill performs network requests and local system inspection, so a loose match can expose data or create outputs the user did not intend.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation states that the skill aggregates data from public APIs and local system metrics but does not warn that using it transmits requests to third-party services and inspects local machine state. Missing disclosure reduces user awareness and can lead to privacy or compliance issues, especially in business environments where system metadata and usage patterns may be sensitive.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest explicitly includes calendar events as part of the daily briefing. In the code, the default sections and fetcher registry only implement date, weather, crypto, news, quote, and system, with no calendar integration at all.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The manifest frames the skill as generating daily briefings from multiple data sources, which implies data retrieval and formatting. The code also persists configuration to a local file and can write generated reports to arbitrary output paths, adding local stateful file-write behavior not reflected in the manifest description.

External Transmission

Medium
Category
Data Exfiltration
Content
def fetch_crypto(coins: list, currency: str = "usd") -> dict:
    """Crypto prices from CoinGecko (free, no API key)."""
    ids = ",".join(coins)
    data = api_get(f"https://api.coingecko.com/api/v3/simple/price?ids={ids}&vs_currencies={currency}&include_24hr_change=true")
    if not data:
        return {"section": "crypto", "error": "Could not fetch crypto prices"}
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
def fetch_quote() -> dict:
    """Inspirational quote from Quotable API."""
    data = api_get("https://api.quotable.io/quotes/random?limit=1")
    if data:
        try:
            j = json.loads(data)
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The NewsData.io API key is accepted on the command line and then stored in plaintext in a JSON config file under the user's home directory. This increases exposure through local file disclosure, backups, shell history, and accidental sharing of the config, potentially allowing unauthorized use of the API key.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The README promotes scheduled reporting, third-party distribution, and aggregation from external sources, but it does not disclose that the skill fetches external data or that generated reports may relay that data into business communication channels. This is dangerous because users may deploy it in automated workflows without understanding the privacy, compliance, or data-sharing implications of periodic outbound requests and downstream redistribution.

Description-Behavior Mismatch

Low
Confidence
85% confidence
Finding
The manifest says the report aggregates weather, crypto prices, news headlines, system health, and calendar events. The implementation instead includes a quote-of-the-day section, which is outside the listed scope and indicates the delivered report content does not fully match the stated description.

Static analysis

No suspicious patterns detected.