Back to skill

Security audit

qweather

Security checks for vulnerabilities and agentic risk

Overview

This weather skill is coherent, but it needs review because its error handling and host configuration can expose the QWeather API key.

Install only if you are comfortable giving the skill a QWeather API key and sending city or coordinate queries to the configured host. Set QWEATHER_API_HOST only to your official QWeather host, avoid running it where stderr is broadly logged, and prefer a patched version that redacts key= values from errors and validates the host before sending requests.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lib/http.ts:36
Finding

API Key Exposure Through Unredacted Error Messages

Content
View full analysis
controller.abort(), timeoutMs); const response = await fetch(urlWithParams, { method: "GET", signal: controller.signal, headers: { Accept: "application/json", }, }); clearTimeout(timer); if (!response.ok) { if (!isLastAttempt && (response.status >= 500 || response.status === 429)) { await sleep(DEFAULT_BACKOFF_MS * 2 ** attempt); continue; } throw new CliError( `HTTP request failed with status ${response.status} for ${urlWithParams}`, ExitCode.NETWORK, ); } try { return await response.json(); } catch (jsonError) { throw new CliError( `Failed to parse JSON response from ${urlWithParams}: ${toErrorMessage(jsonError)}`, ExitCode.NETWORK, { cause: jsonError }, ); } ``` Emission of the error in `scripts/weather.ts`: ```ts void main().catch((error: unknown) => { if (error instanceof CliError) { if (error.rawResponse !== undefined) { printJson(error.rawResponse) ...[truncated 2267 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lib/config.ts:45
Finding

Arbitrary Configured HTTPS Host Can Receive the API Key and Query Data

Content
View full analysis
, context: RuntimeContext, ): Promise { const payload = await context.requestJson({ url: `${context.apiHost}${path}`, params: { ...params, key: context.apiKey }, timeoutMs: context.timeoutMs, retries: context.retries, }); if (!isRecord(payload)) { throw new CliError( "Unexpected API response format", ExitCode.API_BUSINESS, { rawResponse: payload }, ); } ``` ### Technical Analysis `QWEATHER_API_HOST` is trusted as long as it is non-empty. If it does not begin with the exact lowercase string `https://`, the code merely prepends that scheme. It does not parse the result or verify that the destination belongs to QWeather. No restrictions are imposed on: - The hostname or registered domain. - Embedded URL credentials. - The destination port. - Existing paths. - Query strings or fragments. - Loopback, private-network, or link-local destinations. - Redirect behavior after the initial request. Every weather request sends the API key and user-supplied location information t ...[truncated 2319 chars]
Remediation
View remediation
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 (8)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 23)May include surrounding context.

md
2. Run `bun scripts/weather.ts --help` in this skill directory.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill declares required environment variables and is intended to make outbound API requests, but it does not declare an explicit tool scope such as permissions or allowed-tools. That creates a governance gap: the runtime may allow broader env or network access than users and reviewers expect, increasing the risk of secret exposure or unintended external communication.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger list includes broad, everyday phrases like '天气', '气温', '下雨', '预报', and generic '[城市] 天气' patterns, which can cause the skill to activate in casual conversation rather than only on clear user intent. Unintended invocation is less severe here because the skill's function is limited to weather lookup, but it can still lead to unnecessary network calls, surprising behavior, or inadvertent use of configured API credentials.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The validator assigns zh as the default lang when the user does not provide a language. This imposes a specific language choice by default rather than offering a neutral default or requiring explicit user selection, which matches the locale-policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The validator defaults lang to zh for forecast requests when no language is supplied. This hard-codes a language preference without explicit opt-in or documented justification, which is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The flag table sets --lang default to zh, which imposes a specific language choice in the documented interface. The file does not mention that users can choose their preferred language or that Chinese is only a region-specific default, so this can be read as a language-policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code sends a network request and includes the API key as a request parameter, but this file contains no confirmation prompt, user-facing log, or warning comment/docstring indicating that credentials are transmitted to an external service. Because network transmission of credentials is a safety-relevant operation, the lack of any local disclosure matches the missing-warning criterion for code files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This code file is a CLI entrypoint for a weather service and explicitly instructs users to set QWEATHER_API_KEY and QWEATHER_API_HOST, indicating credential use and likely outbound API requests. While the help text mentions the variables, it does not disclose that commands may transmit user-supplied query data and authenticated requests to an external service.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.