Back to skill

Security audit

Weather Reporter

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it silently deletes generic image files in the current working directory and uses external AI/weather services with weak scoping and disclosure.

Review before installing. Run it only in a dedicated folder or virtual environment because it may delete or overwrite common image filenames in the current directory. Treat config.json as sensitive, avoid committing it, and expect city/weather data and prompts to be sent to wttr.in and configured AI providers.

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)

T09 · Insecure Skill Coding Practices

Error
Location
main.py:14
Finding

Import-Time Deletion of Files in the Current Working Directory

Content
View full analysis

Vulnerability Details

File Location: main.py, lines 14-23
Vulnerability Type: Unsafe file deletion and import-time side effects
Risk Level: High

Vulnerable Code

python
try:
    temp_files = ["1.png", "2.png", "3.png", "bg.png", "bg1.png", "bg2.png", "bg3.png",
                  "bg4.png", "bg5.png", "bg6.png", "bg7.png", "bg8.png", "bg9.png",
                  "bg10.png", "bg11.png"]
    for f in temp_files:
        if os.path.exists(f):
            os.remove(f)
except:
    pass

Technical Analysis

The cleanup logic executes at module import time rather than only when the application is explicitly run. Every filename is relative, so Python resolves it against the process's current working directory rather than a dedicated application workspace.

The names are generic and may correspond to unrelated user files. Consequently, importing main.py from another application or running the program from a directory containing files such as 1.png, 2.png, or bg.png can irreversibly delete those files. The unrestricted except block suppresses errors and makes the destructive behavior difficult to diagnose.

Attack Path

  1. A user or integrating application places or already has an unrelated image named 1.png, bg.png, or another listed name in its working directory.
  2. The user executes the Skill from that directory, or another Python component imports main.py.
  3. Python immediately executes the module-level cleanup logic.
  4. Matching files are deleted before the guarded if __name__ == "__main__" workflow begins.
  5. Any deletion errors are silently suppressed.

No attacker-controlled path traversal is required. The vulnerability arises from the collision between generic filenames and the caller's working directory.

Impact Assessment

The code can delete matching files writable by the current process. It does not elevate privileges, so its scope is limited to fil ...[truncated 209 chars]

Remediation
View remediation

Remediation Suggestions

  • Move cleanup into an explicit main() function so importing the module has no destructive side effects.
  • Create a unique temporary workspace with tempfile.TemporaryDirectory() for each run.
  • Resolve every generated path beneath that workspace and verify containment before deletion.
  • Track files created by the current execution and delete only those files.
  • Avoid generic output names in the caller's current working directory.
  • Do not overwrite or delete an existing user file without explicit confirmation.
  • Replace the bare except with specific exception handling and report cleanup failures.

T08 · Insecure Dependencies

Warning
Location
README.md:86
Finding

Unpinned Third-Party Dependencies Permit Mutable Supply-Chain Inputs

Content
View full analysis

Vulnerability Details

File Location: README.md, lines 86-90; SKILL.md, lines 84-88
Vulnerability Type: Unpinned dependency installation
Risk Level: Medium

Vulnerable Code

bash
pip install requests pillow matplotlib scipy pandas openai zhipuai

The same unpinned installation command is documented in both README.md and SKILL.md.

Technical Analysis

The project instructs users to install dependencies without exact versions, cryptographic hashes, or a reviewed lockfile. Package resolution therefore depends on whatever versions the configured package index serves at installation time.

This makes the installed application materially different from the version audited here. A compromised package release, package-index account, dependency chain, or unexpectedly incompatible future version could introduce arbitrary behavior. The reviewed project itself does not contain evidence that any named package is currently malicious; the issue is the mutable and unverifiable installation process.

Attack Path

  1. A user follows the documented pip install command.
  2. pip resolves the latest package versions and their transitive dependencies from the configured index.
  3. A compromised or maliciously updated release is selected because no approved version or hash is enforced.
  4. Package installation hooks or imported package code executes with the user's privileges.
  5. The compromised dependency can access data and resources available to the Python process.

Exploitation depends on compromise or malicious publication within the dependency supply chain.

Impact Assessment

A malicious dependency may execute arbitrary Python code with the privileges of the account installing or running the Skill. Depending on that account's permissions, this may expose project files, configuration-held API keys, network access, generated data, and other user-accessible resources. No privilege escalation beyond ...[truncated 58 chars]

Remediation
View remediation

Remediation Suggestions

  • Add a reviewed dependency manifest with exact versions.
  • Generate a lockfile that includes all transitive dependencies.
  • Require cryptographic hashes, for example with pip install --require-hashes -r requirements.txt.
  • Use a trusted and explicitly configured package index.
  • Regularly scan dependencies for known vulnerabilities and review updates before changing the lockfile.
  • Install dependencies in an isolated virtual environment under a non-privileged account.

T09 · Insecure Skill Coding Practices

Warning
Location
config.json:1
Finding

Reusable API Credentials Are Stored in a Plaintext Project File

Content
View full analysis

Vulnerability Details

File Location: config.json, lines 1-11; AI.py, lines 5-12; makeimage.py, lines 6-17
Vulnerability Type: Plaintext secret storage
Risk Level: Medium

Vulnerable Code

json
{
    "zhipuAI": {
        "api_key": "YOUR_API_KEY",
        "model": "CogView-3-Flash"
    },
    "llm": {
        "api_key": "YOUR_API_KEY",
        "base_url": "https://opencode.ai/zen/v1",
        "model": "minimax-m2.5-free"
    }
}
python
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")
with open(config_path, 'r', encoding='utf-8') as f:
    config = json.load(f)

client = OpenAI(
    api_key=config["llm"]["api_key"],
    base_url=config["llm"]["base_url"])
python
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")
with open(config_path, 'r', encoding='utf-8') as f:
    config = json.load(f)

def generate_image_with_zhipu(weather):
    client = ZhipuAI(api_key=config["zhipuAI"]["api_key"])

Technical Analysis

The distributed file currently contains placeholders rather than live credentials. However, the documented configuration workflow requires users to replace those placeholders with reusable API keys in a plaintext file inside the project directory.

The implementation provides no environment-variable support, operating-system secret-store integration, file-permission validation, or separation between a checked-in example and the user's real secret configuration. Project archives, source-control commits, backups, or other local users may consequently gain access to the credentials.

Attack Path

  1. A user replaces YOUR_API_KEY values in config.json with valid credentials as required for operation.
  2. The project directory is committed to source control, copied into an archive, backed up, shared, or made readable to another local account.
  3. An unauthorized ...[truncated 749 chars]
Remediation
View remediation

Remediation Suggestions

  • Read API keys from environment variables or an operating-system secret manager.
  • Keep only non-sensitive settings such as model names in the tracked configuration file.
  • Distribute a placeholder-only config.example.json rather than instructing users to modify a tracked file.
  • Add the real local secret configuration to .gitignore.
  • Validate that any fallback secret file has restrictive permissions before reading it.
  • Use narrowly scoped credentials where supported and establish a regular rotation process.
  • Immediately revoke and replace any key accidentally committed or shared.

T09 · Insecure Skill Coding Practices

Warning
Location
makeimage.py:32
Finding

Remote Image Is Downloaded Without Origin, Size, Timeout, or Content Validation

Content
View full analysis

Vulnerability Details

File Location: makeimage.py, lines 32-45; downstream parsing at cutimage.py, line 5
Vulnerability Type: Unvalidated and unbounded remote content download
Risk Level: Medium

Vulnerable Code

python
image_url = response.data[0].url
print(f"✅ 图片生成成功: {image_url}")

try:
    img_data = requests.get(image_url).content
    filename = "make.png"
    with open(filename, "wb") as f:
        f.write(img_data)
    print(f"✅ 图片已保存为: {filename}")
except Exception as e:
    print(f"❌ 图片下载失败: {e}")

The resulting file is later parsed as an image:

python
img = Image.open("make.png")

Technical Analysis

The image URL comes from an external API response and is passed directly to requests.get. The request has no connection or read timeout, no status validation, no URL scheme or hostname allowlist, no redirect policy, and no streamed maximum-size enforcement. Accessing .content buffers the entire response in memory before writing it to disk.

The response is not checked for an expected MIME type or validated as an image before being saved. It is subsequently processed by Pillow. A compromised provider response or network endpoint could therefore cause the program to fetch an unexpected URL, follow redirects, consume excessive memory or disk, hang indefinitely, or expose the image parser to malformed content.

The file is also written to the generic relative path make.png, which can overwrite an existing writable file with that name.

Attack Path

  1. The image-generation provider, its account, or the returned response is compromised or manipulated.
  2. The response supplies an attacker-selected URL or a URL that redirects to attacker-controlled content.
  3. The program fetches the URL without validating its host, scheme, redirects, size, or response type.
  4. A very large or non-terminating response exhausts memory, disk, or execution time; alternatively ...[truncated 854 chars]
Remediation
View remediation

Remediation Suggestions

  • Accept only HTTPS URLs from an explicit allowlist of expected image-delivery hosts.
  • Validate every redirect target or disable redirects when they are unnecessary.
  • Configure bounded connection and read timeouts.
  • Call raise_for_status() before consuming the body.
  • Stream the response in chunks and terminate the download when a strict maximum size is exceeded.
  • Validate the response MIME type and use Pillow's verification facilities before normal image processing.
  • Set Pillow decompression-bomb limits appropriate to the expected image dimensions.
  • Save into a dedicated per-run workspace using an exclusive or atomic file-creation method.
  • Do not overwrite a pre-existing make.png outside the controlled workspace.
  • Remove partially downloaded files after any validation or network failure.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (14)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The function sends raw user-provided content to an external LLM endpoint via the configured base_url, but the code contains no notice, consent flow, minimization, or restriction on what may be transmitted. This creates a real privacy and data-governance risk because sensitive user input could be exfiltrated to a third-party or even an attacker-controlled endpoint if configuration is modified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The system message is written in Chinese and instructs the model to respond in that language/format, but the file does not offer the user any language choice. This is a natural-language locale policy concern because it imposes a specific language without opt-in or documented necessity.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README states that weather data comes from wttr.in and that AI services are used for background generation and tips, but it does not clearly warn users that their requested city and related prompt/context will be transmitted to external third-party services. This is a real transparency and privacy issue because users may unknowingly disclose location preferences or contextual inputs to external providers, which can violate user expectations or organizational data-handling requirements.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill description states it fetches weather data from wttr.in and also uses third-party AI APIs, but it does not clearly warn users that city inputs, weather-related prompts, and possibly generated content will be transmitted to external services. This creates a privacy and transparency issue because users may provide location-related or contextual data without understanding it leaves the local environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script deletes a fixed set of files in the current working directory on startup without confirmation, backup, or strong path scoping. If run from an unexpected directory, it can remove unrelated user files with matching names, causing unintended local data loss.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The function documentation states that all weather descriptions and moon phases are returned in Chinese, and the HTTP request explicitly forces lang=zh-cn. This is a natural-language locale policy issue because the skill fixes the output language without any opt-in or user-selectable locale.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The reporting function prints weather summaries entirely in Chinese, and later image labels are also written in Chinese. Because the skill does not appear to offer any locale selection, it effectively forces one language on all users.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code primarily fetches weather data, transforms it, and builds a visual weather report image. At L247 it additionally calls generate_image_with_zhipu on weather descriptions, introducing external AI image generation behavior that is not necessary for basic weather retrieval, charting, or report composition.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Most of the file is dedicated to collecting weather data and rendering charts and labels into an output image. The call to AI((static, dynamic)) adds a separate natural-language recommendation or advice capability, which is not obviously required for producing a weather visualization/report in an unknown-purpose skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code loads an API key from local configuration and sends weather-derived prompt content to a third-party image generation service without any notice, consent flow, or data handling disclosure. While the sample passes only a weather string, in agent use this pattern can transmit user-derived or sensitive contextual data to an external provider, creating privacy, compliance, and unintended data-sharing risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The file hardcodes Chinese-capable fonts and later uses fixed Chinese labels such as '降水量' and '气温曲线', which imposes a specific locale in the rendered output. This is a natural-language policy concern because the skill does not provide any opt-in, configuration, or documented justification for restricting output language.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

README 在功能特性中直接规定“支持任意城市天气查询(英文城市名)”,后文也要求“使用英文名称”,但未说明这是可选限制、未提供语言选择,也没有给出明确的区域/接口约束说明。根据语言/locale 政策,这类强制语言限制应当有用户 opt-in 或合理说明。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

“支持全球任意城市(英文名称)”对输入语言施加了固定限制,但文档没有提供语言/本地化选项,也未解释该约束为何必要。根据规则,强制特定语言而无用户选择属于自然语言层面的语言政策问题。

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation instructs users to place API keys in config.json but does not warn that these credentials are sensitive, should not be committed to source control, and should be protected at rest. This increases the likelihood of accidental credential exposure through screenshots, repository commits, or shared project archives.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.