Back to skill

Security audit

geoskill-water-quality-index

Security checks across malware telemetry and agentic risk

Overview

The main water-quality command is local, but the package bundles undisclosed credential, geocoding, and download helpers, including hardcoded Earthdata credentials.

Review this package before installing. Use only in an isolated environment unless the vendored credential, geocoding, and download modules are removed or clearly documented; rotate the hardcoded Earthdata credential if it is real, and avoid exposing ~/.netrc, ~/.geoskill/secrets.json, or unrelated API keys to this skill.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This is a serious description-behavior mismatch: the skill claims to be an offline water-quality remote-sensing tool, but the analysis indicates hidden geocoding, HTTP download, credential harvesting from environment/.netrc/secrets, and even built-in fallback Earthdata credentials. That creates a trust-boundary violation where users may provide geospatial inputs expecting local processing, while the skill can access secrets and make network requests unrelated to its declared purpose.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The vendored metadata declares a different skill, `landsat-download`, than the advertised water-quality-index capability. This supply-chain mismatch is dangerous because it can hide unexpected functionality, broaden the trusted code surface, and make reviewers believe they are approving analytics-only logic while download-related code is actually included.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The vendored files include `safe_download.py` and `credentials.py`, which introduce network access and credential-handling capabilities beyond what is justified by a pure water-quality computation skill. Even without proof of active abuse in this file alone, unnecessary download and secret-management code increases the attack surface and could enable data exfiltration, unauthorized external access, or misuse of stored credentials if invoked elsewhere.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The code sends user-supplied place queries to third-party geocoding services, which can leak potentially sensitive operational intent, locations of interest, or user-provided identifiers outside the local environment. In a geospatial analysis skill, this is more dangerous because AOIs may correspond to regulated sites, customer assets, or other sensitive targets, and the disclosure happens automatically without strong gating in this file.

Description-Behavior Mismatch

High
Confidence
93% confidence
Finding
This module introduces broad credential-management capability unrelated to the stated water-quality inversion purpose, including access paths for multiple third-party services and local secret stores. In a skill context, unnecessary secret-handling materially expands the attack surface and enables credential harvesting or later misuse if other parts of the skill call these helpers.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
Support for OPENAI_API_KEY is not justified by the skill's declared geospatial water-quality purpose. Access to an unrelated LLM API key is dangerous because it allows the skill to touch higher-value credentials that could be reused for external calls, billing abuse, or data exfiltration in a larger execution chain.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The module supports FIRMS, CMA, and EOG credentials in addition to Earthdata, despite the skill being described as a water-quality inversion tool. Unnecessary multi-service credential access broadens reachable secrets and increases the chance of cross-service abuse or accidental leakage without benefiting the stated task.

Intent-Code Divergence

High
Confidence
97% confidence
Finding
The documentation says passwords are not cached, but load_user_secrets() copies secrets from the user file into the process-wide _DEFAULTS dictionary and leaves them resident for the life of the process. This discrepancy is security-relevant because operators may rely on the claim when assessing memory exposure, long-lived workers, debugging, crash dumps, or unintended reuse across calls/tests.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
Place queries are transmitted to external services without any user-facing disclosure in this file, creating a real privacy and data-sharing risk. Even if the data is 'just a place name,' it can reveal investigative focus, customer locations, or sensitive project context, which is significant in an AOI-resolution component.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
Resolved query data is persisted under the user's home directory without user warning, creating a local privacy exposure and unintended retention of sensitive AOIs. On shared systems or long-lived environments, this can leak historical areas of interest to other local users, admins, backups, or forensic review.

Missing User Warnings

High
Confidence
100% confidence
Finding
The file contains hardcoded fallback credentials, including a plaintext Earthdata username and password. Hardcoded secrets are directly exploitable by anyone with source access, are likely to leak through version control or package distribution, and are especially dangerous here because the skill has no legitimate need to ship live credentials at all.

Credential Access

High
Category
Privilege Escalation
Content
/ `EARTHDATA_TOKEN` / `FIRMS_MAP_KEY` / `OPENAI_API_KEY` /
  `CMA_API_KEY` / `EOG_USERNAME` / `EOG_PASSWORD` 任何一项显式设置
  都优先于默认值。
- **支持 .netrc**:若 ~/.netrc 中存在 `machine urs.earthdata.nasa.gov`
  行,优先取 .netrc 凭证。
- **支持用户级 secrets 文件** ``~/.geoskill/secrets.json``:Phase 7
  (2026-07-27) 新增。本文件在用户 home,**不** vendor 到任何 skill,
Confidence
85% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
/ `EARTHDATA_TOKEN` / `FIRMS_MAP_KEY` / `OPENAI_API_KEY` /
  `CMA_API_KEY` / `EOG_USERNAME` / `EOG_PASSWORD` 任何一项显式设置
  都优先于默认值。
- **支持 .netrc**:若 ~/.netrc 中存在 `machine urs.earthdata.nasa.gov`
  行,优先取 .netrc 凭证。
- **支持用户级 secrets 文件** ``~/.geoskill/secrets.json``:Phase 7
  (2026-07-27) 新增。本文件在用户 home,**不** vendor 到任何 skill,
Confidence
85% confidence
Finding
~/.netrc

Credential Access

High
Category
Privilege Escalation
Content
`CMA_API_KEY` / `EOG_USERNAME` / `EOG_PASSWORD` 任何一项显式设置
  都优先于默认值。
- **支持 .netrc**:若 ~/.netrc 中存在 `machine urs.earthdata.nasa.gov`
  行,优先取 .netrc 凭证。
- **支持用户级 secrets 文件** ``~/.geoskill/secrets.json``:Phase 7
  (2026-07-27) 新增。本文件在用户 home,**不** vendor 到任何 skill,
  **不** push 到 GitHub;用于把个人真实凭证(NASA Earthdata bearer
Confidence
85% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
(2026-07-27) 新增。本文件在用户 home,**不** vendor 到任何 skill,
  **不** push 到 GitHub;用于把个人真实凭证(NASA Earthdata bearer
  token 等)放在 skill 之外。
- **不缓存密码**:每次调用读环境或 .netrc(避免长寿命进程泄露)。
- **统一接口**:`get_earthdata_creds()` / `get_earthdata_token()` /
  `get_firms_key()` / `get_cma_key()` / `get_openai_key()` /
  `get_eog_creds()` 六个 helper。
Confidence
83% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
"EOG_PASSWORD": "",
}

# .netrc 解析(仅在 UNIX-like / WSL 下 ~/.netrc 可用;Windows 下
# 通常用 %USERPROFILE%\_netrc,但 .netrc 本身仍是约定俗成的名称)。
_NETRC_HOSTS = {
    "urs.earthdata.nasa.gov": ("EARTHDATA_USERNAME", "EARTHDATA_PASSWORD"),
Confidence
84% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
"EOG_PASSWORD": "",
}

# .netrc 解析(仅在 UNIX-like / WSL 下 ~/.netrc 可用;Windows 下
# 通常用 %USERPROFILE%\_netrc,但 .netrc 本身仍是约定俗成的名称)。
_NETRC_HOSTS = {
    "urs.earthdata.nasa.gov": ("EARTHDATA_USERNAME", "EARTHDATA_PASSWORD"),
Confidence
84% confidence
Finding
~/.netrc

Credential Access

High
Category
Privilege Escalation
Content
}

# .netrc 解析(仅在 UNIX-like / WSL 下 ~/.netrc 可用;Windows 下
# 通常用 %USERPROFILE%\_netrc,但 .netrc 本身仍是约定俗成的名称)。
_NETRC_HOSTS = {
    "urs.earthdata.nasa.gov": ("EARTHDATA_USERNAME", "EARTHDATA_PASSWORD"),
    "firms.modaps.eosdis.nasa.gov": ("FIRMS_MAP_KEY",),
Confidence
84% 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
Confidence
90% 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
90% 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
88% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
解析顺序:
    1. env: EARTHDATA_USERNAME / EARTHDATA_PASSWORD
    2. ~/.geoskill/secrets.json
    3. .netrc: machine urs.earthdata.nasa.gov
    4. _DEFAULTS 兜底
    """
    u = _resolve_with_netrc("EARTHDATA_USERNAME", "urs.earthdata.nasa.gov", 0)
Confidence
87% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
都优先于默认值。
- **支持 .netrc**:若 ~/.netrc 中存在 `machine urs.earthdata.nasa.gov`
  行,优先取 .netrc 凭证。
- **支持用户级 secrets 文件** ``~/.geoskill/secrets.json``:Phase 7
  (2026-07-27) 新增。本文件在用户 home,**不** vendor 到任何 skill,
  **不** push 到 GitHub;用于把个人真实凭证(NASA Earthdata bearer
  token 等)放在 skill 之外。
Confidence
87% confidence
Finding
secrets.json

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
99% confidence
Finding
secrets.json

Credential Access

High
Category
Privilege Escalation
Content
# 用户级 secrets 文件位置(在用户 home,**不** vendor 到 skill 内部)。
# Phase 7 (2026-07-27): 包含 NASA Earthdata bearer token 等真实凭证。
USER_SECRETS_PATH = Path.home() / ".geoskill" / "secrets.json"

# 是否已加载过用户级 secrets(避免每次调用都重读)
_user_secrets_loaded = False
Confidence
86% confidence
Finding
secrets.json

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