Back to skill

Security audit

geoskill-wind-resource-assessment

Security checks across malware telemetry and agentic risk

Overview

The main wind-analysis tool appears offline, but the package also ships undocumented network geocoding and credential-handling code, including hardcoded Earthdata credentials.

Review this package before installing. The advertised wind assessment command is locally scoped, but the bundled auxiliary modules should be removed, documented, or isolated; hardcoded credentials should be deleted and rotated, network geocoding should require explicit opt-in, vendored provenance should be corrected, and dependencies should be pinned.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This is a significant description-behavior mismatch: the skill presents itself as a local wind-resource assessment tool, but the analyzed code reportedly includes geocoding, generic HTTP downloading, credential management for multiple remote services, and even embedded default Earthdata credentials. Hidden network and credential-handling functionality expands the attack surface, can enable data exfiltration or unauthorized remote access, and violates user expectations for an offline scientific processing skill.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The vendored core metadata claims the bundled code belongs to a different skill ('landsat-download') than the declared wind-resource-assessment skill, which breaks provenance and integrity expectations. This can cause reviewers or tooling to trust, load, or validate the wrong dependency set, and it raises supply-chain concerns because the package contents may have been copied, mislabeled, or substituted without proper verification.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The AOI helper sends user-supplied place names to external geocoding services and can persist results locally, which expands behavior beyond pure offline wind-resource analysis. This creates a real privacy/data-flow issue because user inputs may be disclosed to third parties and retained on disk without clear consent or strong control at the call site.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The documentation claims passwords are not hardcoded, but `_DEFAULTS` embeds a real-looking Earthdata username and password. Hardcoded fallback credentials are dangerous because they expose secrets to anyone with source access and may enable unauthorized access or credential reuse across environments.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The comments say passwords are not cached, but `load_user_secrets()` loads secrets into `_DEFAULTS` and retains them in process memory for reuse. This inconsistency matters because long-lived processes, memory dumps, debugging, or later code paths can access secrets longer than the documentation suggests.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
This module adds place-name resolution and external geocoding behavior to a skill whose declared purpose is wind-resource assessment from wind-speed time series. That scope expansion creates unexpected data egress and enlarges the attack surface through third-party network dependencies, even if the code is not overtly malicious.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The code sends user-supplied place names to external services (Open-Meteo and Nominatim), which is unrelated to the advertised time-series analytics scope and can leak sensitive user queries or operational context. Because it includes automatic fallback and multiple providers, the module increases covert data exfiltration opportunities and makes network behavior harder for users to predict.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The code transmits raw user-provided place queries to Open-Meteo and Nominatim without any in-file disclosure or consent mechanism. Place names can contain sensitive operational, personal, or commercially confidential location information, so sending them to third-party services is a genuine privacy and supply-chain exposure.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
Resolved queries are written to a persistent cache under the user's home directory without an explicit user-facing warning. This can leave sensitive location history on disk, potentially accessible to other local processes, backups, or forensic review long after the task completes.

Missing User Warnings

High
Confidence
99% confidence
Finding
The code embeds fallback credentials directly in `_DEFAULTS`, including a username and password. Even if intended as a convenience fallback, hardcoded credentials are effectively exposed secrets and can be abused by anyone who can read the repository, package, logs, or distributed artifacts.

Missing User Warnings

Medium
Confidence
82% confidence
Finding
The module reads `~/.netrc` and `_netrc` manually and even detects overly broad permissions but does nothing to reject them. Parsing sensitive credential stores without enforcing strict permission checks can expose secrets from insecure files and broadens credential access beyond the immediate skill need.

Credential Access

High
Category
Privilege Escalation
Content
def _read_netrc(host: str) -> Optional[Tuple[str, ...]]:
    """从 ~/.netrc 读指定 host 的凭证(无 token 格式)。"""
    for path in (Path.home() / ".netrc", Path.home() / "_netrc"):
        if not path.is_file():
            continue
Confidence
83% confidence
Finding
~/.netrc

Credential Access

High
Category
Privilege Escalation
Content
def _read_netrc(host: str) -> Optional[Tuple[str, ...]]:
    """从 ~/.netrc 读指定 host 的凭证(无 token 格式)。"""
    for path in (Path.home() / ".netrc", Path.home() / "_netrc"):
        if not path.is_file():
            continue
        try:
Confidence
83% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
def _resolve_with_netrc(env_name: str, netrc_host: str, field_index: int) -> str:
    """env > 用户 secrets > .netrc > 默认."""
    env_val = os.environ.get(env_name, "").strip()
    if env_val:
        return env_val
Confidence
80% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
_DEFAULTS: dict[str, str] = {
    "EARTHDATA_USERNAME": "ruiduobao",
    "EARTHDATA_PASSWORD": "Ruiduobao123",
    "EARTHDATA_TOKEN": "",  # 用户级 secrets.json 提供(不走默认值以免推到 GitHub)
    "FIRMS_MAP_KEY": "",
    "CMA_API_KEY": "",
    "OPENAI_API_KEY": "",
Confidence
93% confidence
Finding
secrets.json

Credential Access

High
Category
Privilege Escalation
Content
def load_user_secrets(path: Optional[Path] = None, *, force: bool = False) -> bool:
    """从 ``~/.geoskill/secrets.json`` 加载用户级凭证到 _DEFAULTS.

    Phase 7 (2026-07-27): 第一次调用自动加载(lazy)。之后每个 helper
    调用也会 lazy 加载,除非显式 ``force=True`` 强制重读。返回 True
Confidence
81% confidence
Finding
secrets.json

Unpinned Dependencies

Low
Category
Supply Chain
Content
numpy
rasterio
scipy
Confidence
95% confidence
Finding
numpy

Unpinned Dependencies

Low
Category
Supply Chain
Content
numpy
rasterio
scipy
Confidence
95% confidence
Finding
rasterio

Unpinned Dependencies

Low
Category
Supply Chain
Content
numpy
rasterio
scipy
Confidence
95% confidence
Finding
scipy

Known Vulnerable Dependency: numpy — 10 advisory(ies): CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +7 more

Critical
Category
Supply Chain
Confidence
89% confidence
Finding
numpy

Known Vulnerable Dependency: scipy — 4 advisory(ies): CVE-2013-4251 (SciPy creates insecure temporary directories); CVE-2013-4251 (The scipy.weave component in SciPy before 0.12.1 creates insecure temporary dire); CVE-2023-25399 (A refcounting issue which leads to potential memory leak was discovered in scipy) +1 more

High
Category
Supply Chain
Confidence
87% confidence
Finding
scipy

VirusTotal

VirusTotal findings are pending for this skill version.

View on VirusTotal

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/conftest.py:15