Back to skill

Security audit

Weather TV style

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it advertises, but its installer modifies the host Python environment and it sends precise location details to external services without strong user-facing disclosure.

Review this skill before installing. Prefer running it in an isolated virtual environment, avoid using private street addresses unless you are comfortable sending them to Gemini and Open-Meteo, and consider city-level or rounded-coordinate inputs where possible.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:4
Finding

Unpinned Dependencies Installed into the Host Python Environment

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:4
Vulnerability Type: T08: Insecure Dependencies
Risk Level: Medium

Vulnerable Code:

yaml
metadata: {"clawdbot":{"emoji":"📺","requires":{"env":["GEMINI_API_KEY"]},"install":[{"id":"pip-google-ai","kind":"exec","command":"pip install -U google-generativeai requests --break-system-packages","label":"Install dependencies"}]}}

Technical Analysis

The installation command retrieves the latest available versions of google-generativeai and requests without version constraints or integrity hashes. The -U option permits reviewed dependency versions to be replaced by future releases, making installation behavior non-reproducible and expanding supply-chain exposure.

The --break-system-packages option bypasses Python distribution safeguards and installs or upgrades packages in the host environment. This exceeds the privileges necessary for the Skill because the dependencies can instead be installed in an isolated virtual environment.

There is also a dependency consistency issue: the script imports google.genai, while the documented installer specifies google-generativeai. The imported interface is generally supplied by the newer google-genai distribution. Depending on the existing environment, this can cause runtime failure or reliance on an undeclared package.

Attack Path

  1. The Skill installation command runs with access to the host Python environment.
  2. Pip resolves the latest unpinned package releases from its configured package index.
  3. A compromised or otherwise unsafe future release can be selected without requiring a change to the audited Skill.
  4. Package installation or import-time initialization executes code with the privileges of the user running the installation.
  5. Because system-package protections are bypassed, the installation can also replace dependencies used by unrelated applications.

Impact Assessment

A ...[truncated 541 chars]

Remediation
View remediation

Remediation Suggestions

  • Install dependencies in a dedicated virtual environment rather than using --break-system-packages.
  • Remove -U from routine Skill execution and installation instructions.
  • Declare the distribution that actually provides google.genai, and verify it against the script's supported API.
  • Pin reviewed versions, for example through a locked requirements file.
  • Use package hashes with pip install --require-hashes where practical.
  • Run dependency vulnerability and provenance checks during release preparation.
  • Perform installation with an unprivileged account and avoid modifying the host's system Python environment.

other

Warning
Location
scripts/generate_infographic.py:46
Finding

Precise User Location Is Disclosed to External Services

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_infographic.py:46-57, 93-105, 122-143
Vulnerability Type: other: Sensitive Location Data Disclosure
Risk Level: Medium

Vulnerable Code:

python
def fetch_weather(lat, lon, timezone="auto"):
    params = {
        "latitude": lat,
        "longitude": lon,
        "current": "temperature_2m,apparent_temperature,relative_humidity_2m,precipitation,weather_code,wind_speed_10m,wind_direction_10m,uv_index,is_day",
        "daily": "temperature_2m_max,temperature_2m_min,precipitation_probability_max,weather_code,wind_speed_10m_max,wind_direction_10m_dominant,uv_index_max,sunrise,sunset",
        "forecast_days": 7,
        "timezone": timezone
    }
    resp = requests.get(OPEN_METEO_URL, params=params)
python
client = genai.Client(api_key=api_key, http_options={'api_version': 'v1alpha'})

season = get_current_season(lat)
weather_data = fetch_weather(lat, lon)

# Step 1: Generate Background
bg_prompt = f"Generate a photorealistic high-resolution landscape photograph of {address} during {season}. Professional aerial scenery, wide angle, clean and uncluttered, suitable as a TV weather broadcast backdrop. No text, no people."
print(f"Generating background for {address} ({season})...")

bg_response = client.models.generate_content(
    model='gemini-3-pro-image-preview',
    contents=bg_prompt,
    config=types.GenerateContentConfig(
        response_modalities=["IMAGE"],
    )
)
python
infographic_prompt = f"""
MASTER PROMPT: Photorealistic TV weather broadcast frame.
Studio environment with a curved video wall displaying the provided background image of {address}.
Overlay a professional broadcast UI with the following weather data:
- Location: {address}
- Current: {weather_data['temp']}°C, {weather_data['weather']}, Wind {weather_data['wind_speed']}km/h {weather_data['wind_dir']}°
- 7-Day Forecast: {
...[truncated 2243 chars]
Remediation
View remediation

Remediation Suggestions

  • Clearly disclose before execution that coordinates are sent to Open-Meteo and address text and image content are sent to Google Gemini.
  • Obtain explicit user consent before transmitting a precise address.
  • Permit city-level, postal-region, landmark, or rounded-coordinate inputs.
  • Separate the private lookup location from the public display label.
  • Avoid including the exact address in the second Gemini request when a coarse label is sufficient.
  • Document the relevant providers' privacy, retention, and geographic-processing implications.
  • Consider local composition of the forecast overlay so that forecast data and the address do not need to be sent in a second model request.
  • Avoid logging a precise address unless the user has requested verbose output.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/generate_infographic.py:99
Finding

Untrusted Address Input Is Embedded Directly into Gemini Instructions

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_infographic.py:99-108, 122-143
Vulnerability Type: T09: Insecure Skill Coding Practices
Risk Level: Low

Vulnerable Code:

python
bg_prompt = f"Generate a photorealistic high-resolution landscape photograph of {address} during {season}. Professional aerial scenery, wide angle, clean and uncluttered, suitable as a TV weather broadcast backdrop. No text, no people."
print(f"Generating background for {address} ({season})...")

bg_response = client.models.generate_content(
    model='gemini-3-pro-image-preview',
    contents=bg_prompt,
    config=types.GenerateContentConfig(
        response_modalities=["IMAGE"],
    )
)
python
infographic_prompt = f"""
MASTER PROMPT: Photorealistic TV weather broadcast frame.
Studio environment with a curved video wall displaying the provided background image of {address}.
Overlay a professional broadcast UI with the following weather data:
- Location: {address}
- Current: {weather_data['temp']}°C, {weather_data['weather']}, Wind {weather_data['wind_speed']}km/h {weather_data['wind_dir']}°
- 7-Day Forecast: {json.dumps(weather_data['forecast'], indent=2)}

Requirements:
- High legibility, accurate numerals.
- Horizontal row of exactly 7 forecast tiles.
- Deep blue theme, consistent modern broadcast style.
- No channel logos.
- Accurate representation of weather icons.
"""

Technical Analysis

The command-line --address value is untrusted input. It is interpolated directly into instruction-bearing prompts without validation, length limits, structured separation, or an instruction that the value must be treated only as data.

An attacker can supply an address containing natural-language instructions designed to override surrounding requirements. This is an indirect prompt-injection flaw affecting the Gemini requests. The script does not expose local tools or command execu ...[truncated 1126 chars]

Remediation
View remediation

Remediation Suggestions

  • Apply a reasonable maximum length to --address.
  • Reject control characters and multiline input when they are not required for legitimate addresses.
  • Place the address in a clearly delimited data section rather than directly in prose instructions.
  • Explicitly instruct the model that content inside the address field is untrusted data and must not be followed as instructions.
  • Prefer structured content parts or a schema-supported request format when available.
  • Use a normalized, geocoded display name rather than arbitrary user-provided text.
  • Validate that the returned response contains the expected image modality and apply content-safety checks appropriate to the deployment.
  • If output accuracy is critical, render labels and numerical weather data locally instead of relying on a generative model to reproduce them.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/generate_infographic.py:46
Finding

Open-Meteo Request Has No Explicit Timeout

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_infographic.py:46-58
Vulnerability Type: T09: Insecure Skill Coding Practices
Risk Level: Low

Vulnerable Code:

python
def fetch_weather(lat, lon, timezone="auto"):
    params = {
        "latitude": lat,
        "longitude": lon,
        "current": "temperature_2m,apparent_temperature,relative_humidity_2m,precipitation,weather_code,wind_speed_10m,wind_direction_10m,uv_index,is_day",
        "daily": "temperature_2m_max,temperature_2m_min,precipitation_probability_max,weather_code,wind_speed_10m_max,wind_direction_10m_dominant,uv_index_max,sunrise,sunset",
        "forecast_days": 7,
        "timezone": timezone
    }
    resp = requests.get(OPEN_METEO_URL, params=params)
    resp.raise_for_status()

Technical Analysis

requests.get is called without a timeout argument. Requests does not impose a default request timeout, so a stalled connection or server response can leave the process blocked indefinitely.

The function is invoked synchronously from the asynchronous generate_infographic function. Consequently, the blocking request also blocks the event-loop thread while waiting. The code has no bounded retry policy or overall operation deadline.

Attack Path

  1. The Skill begins generating an infographic and invokes fetch_weather.
  2. The Open-Meteo endpoint, a network intermediary, or the local network accepts the connection but stalls.
  3. Because no timeout is configured, the call remains blocked.
  4. The Skill does not progress to image generation or return control to the caller.
  5. Repeated stalled invocations can consume worker processes or task slots and reduce service availability.

Impact Assessment

Exploitation or adverse network behavior can cause denial of service for the current invocation and consume execution resources in an automated deployment. It does not provide filesystem access, code ex ...[truncated 224 chars]

Remediation
View remediation

Remediation Suggestions

  • Add separate connect and read timeouts, for example:
    python
    resp = requests.get(
        OPEN_METEO_URL,
        params=params,
        timeout=(5, 20),
    )
    
  • Catch requests.Timeout and requests.RequestException and return a controlled error.
  • Use a bounded retry policy with exponential backoff only for transient failures.
  • Add an overall deadline for the complete weather and image-generation workflow.
  • If retaining asynchronous orchestration, use an asynchronous HTTP client or move blocking network work to a worker thread.
  • Avoid unlimited retries, which would reintroduce availability and resource-exhaustion risk.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares environment-variable and network capabilities in metadata but does not constrain tool scope with explicit permissions or allowed-tools. That creates an overbroad execution surface: the agent may permit more tool access than is necessary, increasing the chance of unintended outbound requests, secret exposure, or capability abuse if the skill or its dependencies are modified or behave unexpectedly.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
82% confidence
Finding

The code is hardwired to transmit location data to an external weather service, which creates a privacy and data-governance risk because user location information leaves the local trust boundary. The use of HTTPS reduces network interception risk, but the core issue is third-party disclosure of potentially sensitive geolocation data.

Content

Scanner excerpt · scripts/generate_infographic.py (reported line 12)May include surrounding context.

python
import requests

# Constants
OPEN_METEO_URL = "https://api.open-meteo.com/v1/forecast"
WEATHER_CODES = {
    0: 'Clear sky', 1: 'Mainly clear', 2: 'Partly cloudy', 3: 'Overcast',
    45: 'Foggy', 48: 'Depositing rime fog', 51: 'Light drizzle',

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill sends the user-provided address directly to Google's generative image API in prompts and uses precise latitude/longitude with Open-Meteo, which discloses potentially sensitive location data to third parties. In a weather infographic skill this data flow is functionally necessary, but the lack of explicit user-facing notice or minimization means a user may unknowingly expose home or work addresses.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.