Back to skill

Security audit

Eternal Daily Briefing

Security checks for vulnerabilities and agentic risk

Overview

This daily briefing skill is not malicious, but its section-only commands still contact all configured services and read local data before hiding unused results.

Review this skill before installing if you expect section-only commands to be private or offline. A full daily briefing matches the advertised purpose, but narrow modes still send configured location, news interests, and market symbols to external providers and read local briefing files unless the script is changed.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/briefing.py:293
Finding

Section-Specific Modes Perform Unnecessary Local Data Access and External Network Requests

Content
View full analysis

Vulnerability Details

File Location: scripts/briefing.py, lines 293–323
Vulnerability Type: Least-privilege violation and unnecessary data disclosure
Risk Level: Medium

Vulnerable Code

python
    # Fetch all data
    weather = get_weather(config['location'])
    news = get_news(config['news_topics'], config.get('news_region', 'US'))
    
    all_symbols = config.get('crypto', []) + config.get('stocks', []) + config.get('forex', [])
    markets = get_market_data(all_symbols)
    
    tasks = get_todays_tasks()
    events = get_todays_events()
    
    # Filter if specific section requested
    section = None
    if args.weather: section = 'weather'
    elif args.news: section = 'news'
    elif args.crypto: section = 'crypto'
    elif args.tasks: section = 'tasks'
    
    if section == 'weather':
        news, markets, tasks, events = [], [], [], []
    elif section == 'news':
        weather, markets, tasks, events = None, [], [], []
    elif section == 'crypto':
        weather, news, tasks, events = None, [], [], []
        markets = [m for m in markets if '-USD' in m['symbol']]
    elif section == 'tasks':
        weather, news, markets, events = None, [], [], []

Technical Analysis

The program invokes every data collector before determining which section the user requested. The filtering at lines 308–323 only removes collected values from the final output; it does not prevent the underlying file reads or network requests.

For example, invoking the local-only --tasks mode still:

  • Sends the configured location to wttr.in.
  • Sends configured topics and region information to Google News.
  • Sends configured cryptocurrency, stock, and foreign-exchange symbols through yfinance.
  • Reads the local events.json file even though events are not requested.

The same issue affects the other section-specific modes. This violates least-privilege and data-minimization principles because each mode accesses resources unre ...[truncated 2190 chars]

Remediation
View remediation

Remediation Suggestions

Determine the requested section before collecting any data, and invoke only the collector required for that mode.

A hardened implementation should:

  1. Parse and resolve mutually exclusive section options before any collector is called.
  2. Initialize unrequested results to None or empty lists.
  3. Call get_weather() only for the full briefing or --weather.
  4. Call get_news() only for the full briefing or --news.
  5. Call get_market_data() only for the full briefing or --crypto; for --crypto, pass only configured cryptocurrency symbols.
  6. Read tasks and events only when those sections are required.
  7. Use an argparse mutually exclusive group so conflicting section flags cannot be supplied together.
  8. Add tests that mock network and file operations and verify that each section-specific mode touches only its documented data sources.

Example restructuring:

python
    section = None
    if args.weather:
        section = 'weather'
    elif args.news:
        section = 'news'
    elif args.crypto:
        section = 'crypto'
    elif args.tasks:
        section = 'tasks'

    weather = None
    news = []
    markets = []
    tasks = []
    events = []

    if section is None or section == 'weather':
        weather = get_weather(config['location'])

    if section is None or section == 'news':
        news = get_news(
            config['news_topics'],
            config.get('news_region', 'US')
        )

    if section is None:
        all_symbols = (
            config.get('crypto', [])
            + config.get('stocks', [])
            + config.get('forex', [])
        )
        markets = get_market_data(all_symbols)
        tasks = get_todays_tasks()
        events = get_todays_events()
    elif section == 'crypto':
        markets = get_market_data(config.get('crypto', []))
    elif section == 'tasks':
        tasks = get_todays_tasks()

The documentation should also be corrected so that advertised options accur ...[truncated 47 chars]

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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises executable usage that performs network access and reads/writes local user files, but it does not declare any explicit tool scope or permissions boundaries. That creates an authorization ambiguity where an agent may invoke capabilities broader than the user expects, especially because the skill aggregates personal local data and external content in one flow.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The invocation phrases are broad and overlap with common assistant requests like 'what's happening today' or 'give me my briefing,' which can trigger the skill unintentionally. Because this skill pulls together personal files and external sources, accidental activation can expose or process sensitive user context without clear intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description explains data sources and configuration but does not warn users that it aggregates local personal data like tasks/events and may transmit contextual parameters to third-party services such as weather, news, and finance providers. This omission increases privacy risk because users may not realize that a simple briefing request can combine sensitive local information with external network calls.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script sends user-configured data such as location, news topics, and market interests to third-party services (wttr.in, Google News, Yahoo Finance) without any explicit user notice, consent flow, or privacy boundary. In a daily-briefing skill, these values can reveal sensitive behavioral or geographic information, and the risk is amplified because the requests happen automatically as part of normal use or scheduled runs.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.