Back to skill

Security audit

和风天气查询功能

Security checks for vulnerabilities and agentic risk

Overview

This weather skill is mostly weather-related, but it needs review because it can silently send location queries to an undisclosed provider and includes a utility that can print live QWeather tokens.

Review before installing. Use this only in an environment where sending queried locations to external weather services is acceptable, remove or gate the Open-Meteo fallback unless users opt in, and do not run the token generator in logged environments unless it is changed to redact JWTs. Replace the bundled private-key-shaped placeholder with clear setup documentation and keep real QWeather private keys outside the skill package.

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
lib/gen_qweather_token.js:58
Finding

Live QWeather Bearer JWT Exposed Through Standard Output

Content
View full analysis

Vulnerability Details

File Location: lib/gen_qweather_token.js:58-63
Vulnerability Type: Sensitive credential exposure through logging
Risk Level: Medium

Vulnerable Code

js
const { token, payload } = generateJwtEd25519(CONFIG.PROJECT_ID, CONFIG.CREDENTIALS_ID, CONFIG.PRIVATE_KEY_PATH);

console.log("JWT TOKEN:");
console.log(token);
console.log("\nPayload preview:");
console.log(payload);

Technical Analysis

The token-generation utility writes the complete signed QWeather JWT to standard output. This JWT is used as a bearer credential and can therefore be replayed by anyone who obtains it while it remains valid.

Standard output is commonly captured by CI systems, process supervisors, terminal recording software, container logs, and centralized logging platforms. Consequently, printing the token unnecessarily expands access to an authentication credential beyond the process that generated it.

The generated token has an approximately 15-minute lifetime. The checked-in project currently contains placeholder identifiers and a malformed sample private-key file, so successful exploitation requires an operator first to configure valid QWeather credentials. Once configured, however, running this utility produces the disclosure directly.

Attack Path

  1. An operator replaces the placeholder QWeather configuration and key material with valid credentials.
  2. The operator runs lib/gen_qweather_token.js to test JWT generation.
  3. The process prints the complete signed bearer JWT to standard output.
  4. A CI service, terminal recorder, process supervisor, or centralized logging system retains the output.
  5. An unauthorized party with access to those logs extracts the JWT.
  6. The party replays the token against the configured QWeather API before its expiration.

Impact Assessment

An attacker who obtains the logged token can temporarily exercise the QWeather API permissions associa ...[truncated 398 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove console.log(token) and never print complete bearer credentials by default.
  2. Display only non-sensitive metadata, such as the expiration time, subject, and a one-way token fingerprint.
  3. If raw token output is operationally unavoidable, require an explicit command-line option and display a prominent warning before emitting it.
  4. Ensure CI and production logging configurations redact JWT-shaped values and Authorization headers.
  5. Restrict access to process and build logs and configure short retention periods.
  6. Document that generated JWTs are sensitive credentials and must not be copied into tickets, chat messages, or persistent logs.

other

Note
Location
lib/qweather_weather_tool.js:13
Finding

Undocumented Disclosure of User Location Data to Open-Meteo

Content
View full analysis

Vulnerability Details

File Locations:

  • lib/qweather_weather_tool.js:13-20
  • lib/qweather_weather_tool.js:40-48
  • lib/qweather_weather_tool.js:65-73
  • lib/weather_now_openmeteo.js:12-25

Vulnerability Type: Undisclosed third-party data disclosure
Risk Level: Low

Vulnerable Code

QWeather location-resolution failures activate the fallback:

js
const resolved = await qweather_location_lookup({ location: loc });
if (!resolved.success) {
  try {
    const { weather_now_openmeteo } = require("./weather_now_openmeteo");
    return await weather_now_openmeteo({ location: loc });
  } catch (fallbackError) {
    return {
      success: false,
      error: `Location lookup failed: ${resolved.error}, fallback also failed: ${fallbackError.message}`
    };
  }
}

QWeather API error responses also activate it:

js
if (data?.code !== "200") {
  try {
    const { weather_now_openmeteo } = require("./weather_now_openmeteo");
    return await weather_now_openmeteo({ location: loc });
  } catch (fallbackError) {
    return {
      success: false,
      error: `Weather API error (${data?.code}), fallback also failed: ${fallbackError.message}`
    };
  }
}

Network exceptions activate the same fallback:

js
} catch (error) {
  try {
    const { weather_now_openmeteo } = require("./weather_now_openmeteo");
    return await weather_now_openmeteo({ location: loc });
  } catch (fallbackError) {
    return {
      success: false,
      error: `Weather request failed: ${error.message}, fallback also failed: ${fallbackError.message}`
    };
  }
}

The fallback sends the original location and subsequently resolved coordinates to Open-Meteo:

js
const geocodeResponse = await axios.get('https://geocoding-api.open-meteo.com/v1/search', {
  params: { name: inputLoc },
  timeout: 10000
});

if (geocodeResponse.data.results && ge
...[truncated 2443 chars]
Remediation
View remediation

Remediation Suggestions

  1. Explicitly document Open-Meteo as a fallback provider in SKILL.md, including which user data is transmitted.
  2. Require affirmative user consent before sending a location to a provider other than QWeather.
  3. Add a configuration option such as ENABLE_OPEN_METEO_FALLBACK, defaulting to disabled.
  4. When fallback is disabled, return the documented QWeather error instead of transferring the request elsewhere.
  5. Clearly identify the selected provider in the returned result before presenting its data to the user.
  6. Validate coordinate ranges and minimize location precision when exact coordinates are unnecessary.
  7. Document the privacy implications of sending place names or coordinates to each external service.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (41)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

A skill whose declared purpose is weather lookup but whose actual behavior reportedly generates JWTs, reads a private key from disk, and outputs authentication material creates a severe trust-boundary violation. Hidden credential handling and token disclosure can expose secrets and enable misuse of external services well beyond the stated weather-query scope.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

A skill whose declared purpose is weather lookup but whose actual behavior reportedly generates JWTs, reads a private key from disk, and outputs authentication material creates a severe trust-boundary violation. Hidden credential handling and token disclosure can expose secrets and enable misuse of external services well beyond the stated weather-query scope.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

A skill whose declared purpose is weather lookup but whose actual behavior reportedly generates JWTs, reads a private key from disk, and outputs authentication material creates a severe trust-boundary violation. Hidden credential handling and token disclosure can expose secrets and enable misuse of external services well beyond the stated weather-query scope.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

A skill whose declared purpose is weather lookup but whose actual behavior reportedly generates JWTs, reads a private key from disk, and outputs authentication material creates a severe trust-boundary violation. Hidden credential handling and token disclosure can expose secrets and enable misuse of external services well beyond the stated weather-query scope.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

A skill whose declared purpose is weather lookup but whose actual behavior reportedly generates JWTs, reads a private key from disk, and outputs authentication material creates a severe trust-boundary violation. Hidden credential handling and token disclosure can expose secrets and enable misuse of external services well beyond the stated weather-query scope.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

A skill whose declared purpose is weather lookup but whose actual behavior reportedly generates JWTs, reads a private key from disk, and outputs authentication material creates a severe trust-boundary violation. Hidden credential handling and token disclosure can expose secrets and enable misuse of external services well beyond the stated weather-query scope.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

A skill whose declared purpose is weather lookup but whose actual behavior reportedly generates JWTs, reads a private key from disk, and outputs authentication material creates a severe trust-boundary violation. Hidden credential handling and token disclosure can expose secrets and enable misuse of external services well beyond the stated weather-query scope.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The repository contains a file presented as an Ed25519 private key artifact even though the skill’s declared purpose is only weather querying. Shipping private-key material or key-related artifacts in an unrelated skill expands the attack surface, suggests secret-handling failures, and could enable unauthorized signing or trust abuse if a real key is later substituted or if reviewers miss the discrepancy.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

An asymmetric private-key capability is not justified by a weather-query skill, making its presence highly suspicious and security-relevant. Even though the body contains command text instead of valid PEM data, the file name, header/footer, and packaging pattern normalize inclusion of private-key artifacts and could conceal later insertion of real signing material or facilitate misuse in downstream automation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding

The skill relies on environment-based secrets and configuration such as QWEATHER_DEFAULT_LOCATION and the documented QWEATHER_* credentials, but it does not declare any explicit tool or permission scope for env access. Undeclared environment access weakens least-privilege controls and can cause operators and users to underestimate what sensitive runtime data the skill may read.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger terms are broad enough to activate on many casual mentions of weather-related words, which can cause unintended skill invocation and unexpected access to configured defaults or external tools. In context, this is more dangerous because the skill may read environment configuration and automatically act without the user clearly requesting a weather lookup.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file wraps a shell command inside BEGIN/END PRIVATE KEY markers, which misrepresents its contents and can mislead human reviewers or simplistic tooling. In the context of an unrelated weather skill, this contradiction is dangerous because it looks like an attempt to disguise suspicious content, bypass detection heuristics, or condition maintainers to accept secret-like artifacts in the repository.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script prints a freshly generated JWT derived from the configured private key directly to stdout. In many real environments stdout is captured by terminals, shell history, CI logs, process supervisors, or shared observability systems, so exposing the bearer token can allow unintended reuse during its validity window.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
78% confidence
Finding

The human-readable docstring and inline comments are written only in Chinese, which imposes a specific language context without any indication that users can choose another language. Under the stated policy, language constraints should be optional or explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The only natural-language documentation in this file is written in Chinese, including the function description and parameter comments, without indicating that language selection is optional or user-configurable. Under the stated policy, forcing a specific language without opt-in can be a locale/language policy violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest describes the skill as providing 实时天气与未来预报 using QWeather, but this file implements retrieval of 生活指数 data from the QWeather Indices API instead of current weather or forecast data. Lifestyle indices are adjacent to weather data but still a distinct product/capability not stated in the manifest description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The manifest describes the skill as providing real-time weather and future forecasts via QWeather, but this file specifically adds a dedicated minute-level precipitation API capability. That is a materially different weather product not mentioned in the manifest description, so the implemented behavior exceeds the stated scope rather than being a mere implementation detail.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest description limits the skill to '实时天气与未来预报' using QWeather, but this function queries the /v7/warning/now endpoint for meteorological disaster alerts after resolving a location. Warning/alert retrieval is a distinct user-facing capability not described in the manifest, so the implemented behavior exceeds the claimed scope.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

When QWeather location resolution fails, the function silently sends the user-provided location to a different provider (Open-Meteo) without any disclosure or consent. This creates a data-flow and trust-boundary change: users and integrators expecting only QWeather may unknowingly expose location data to a second third party, which can violate privacy expectations, compliance assumptions, or provider-specific data handling requirements.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The fallback path transmits user location data to a second external provider that is not described in the skill metadata, creating undisclosed third-party sharing. In a weather skill, location data is sensitive enough that silent forwarding to another provider can create privacy, contractual, or jurisdictional exposure even if the data seems routine.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

If the QWeather current-weather API returns a non-200 application code, the code silently retries with Open-Meteo, again sending the same location to another external service without notice. This is dangerous because failures in one provider automatically trigger undisclosed cross-provider data sharing, undermining user expectations and making auditing of data recipients harder.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest says the skill supports city name, LocationID, and latitude/longitude, and can obtain both real-time weather and future forecasts. This file always performs a city lookup from a single location string and then calls only the /weather/now endpoint, with no path for direct LocationID, coordinate handling, or forecast retrieval.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The function transmits inputLoc and derived location identifiers to QWeather over HTTP, which is a data-sharing action with a third party. While the code comments describe the API usage, there is no confirmation prompt or explicit user-facing warning/log indicating that the user's queried location will be sent externally.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest says the skill uses 和风天气(QWeather, JWT+Host)to obtain current weather and forecasts, but this file implements weather lookup via Open-Meteo geocoding and forecast endpoints instead. That is a semantic mismatch in provider behavior, especially because the manifest specifically names the backend and authentication approach.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

The function sends user-supplied or environment-derived location data to third-party Open-Meteo endpoints, which is an external data transmission. In a weather skill this is expected, but it still has privacy implications because potentially sensitive location information is disclosed to an external service without any visible minimization, consent handling, or provider disclosure in this file.

Content

Scanner excerpt · lib/weather_now_openmeteo.js (reported line 22)May include surrounding context.

js
const location = geocodeResponse.data.results[0];
      
      // 使用坐标获取天气数据
      const weatherResponse = await axios.get('https://api.open-meteo.com/v1/forecast', {
        params: {
          latitude: location.latitude,
          longitude: location.longitude,

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
lib/weather_now_free.js:9

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
lib/weather_now_openmeteo.js:9