Back to skill

Security audit

geoskill-forest-cover-change

Security checks across malware telemetry and agentic risk

Overview

The main forest-change tool is local, but the package bundles unrelated credential and network helper code, including a hardcoded Earthdata fallback password.

Install only if you are comfortable with a skill package that includes extra geospatial helper code capable of network geocoding, local AOI caching, and reading common credential locations. For normal use, run the documented entrypoint with local files or --synthetic, and avoid invoking the bundled credential/geocoding/download helpers unless you have reviewed and scoped them.

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 Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (35)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill declares an offline/local NDVI workflow, yet static analysis detected capabilities for environment access, file read/write, shell, and network without corresponding permission disclosure. Undeclared powerful capabilities increase the risk of secret access, unexpected command execution, or data exfiltration because users and hosts cannot accurately assess what the skill may do.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented purpose is narrow forest-cover change detection, but the analyzed behavior reportedly includes geocoding/network calls, arbitrary URL downloading, credential collection from environment/.netrc/secrets, hardcoded default credentials, and unrelated remote-sensing registries. This mismatch is dangerous because hidden or unrelated functionality can be used to fetch and execute untrusted inputs, access secrets, or exfiltrate data under the cover of a benign geospatial skill.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
This AOI helper expands the skill’s behavior beyond offline forest-cover analysis by transmitting user-supplied place names to third-party geocoding services and persisting results locally. That creates an undeclared data-flow and persistence surface: sensitive locations or project names may leave the local environment and be stored on disk, which is a real privacy and supply-chain concern even if not directly code-execution.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The code contacts Open-Meteo and Nominatim despite the skill being described as NDVI-based forest-change analysis. In this context, unexpected outbound requests are dangerous because they can disclose user AOIs, violate offline/air-gapped expectations, and introduce dependency on untrusted third-party services for a task the manifest does not advertise.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
This module exposes broad credential-access capabilities that are not necessary for the stated forest-cover-change skill, including access to multiple unrelated external services. In a skill/plugin context, overbroad secret access increases blast radius: any downstream code that imports this helper can retrieve credentials from environment variables, user secrets files, or .netrc and potentially misuse them.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
Providing OpenAI API key access is unrelated to NDVI-based forest-cover change detection and creates an unnecessary path to high-value credentials. In agent ecosystems, LLM API keys are especially sensitive because they can be used immediately for billable abuse or as a conduit for exfiltration through external API calls.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The module supports CMA, FIRMS, and EOG credentials beyond the narrowly declared forest-change purpose, expanding secret-access scope without clear justification in this file. Even if some geospatial ecosystems may use such services, bundling them together in one generic credential broker makes accidental or unauthorized credential reuse easier.

Intent-Code Divergence

Medium
Confidence
88% confidence
Finding
The documentation says passwords are not cached, but load_user_secrets() copies secrets into the module-level _DEFAULTS table and keeps them in process memory for the process lifetime unless changed. In long-lived agent processes, this increases exposure to memory disclosure, unintended reuse, and cross-component secret access beyond the original call site.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
User-supplied place queries are sent to external geocoding providers without any disclosure in this file. That is dangerous because AOI names may encode sensitive sites, field locations, or internal project targets, and silent transmission to third parties can violate privacy expectations, policy, or regulatory requirements.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
Resolved queries are written to a cache directory under the user’s home directory without warning or explicit opt-in. Persistent storage of AOI manifests can leak sensitive location history to other local users, backup systems, or forensic review, especially on shared workstations or managed endpoints.

Natural-Language Policy Violations

Medium
Confidence
75% confidence
Finding
Hard-coding Chinese language preferences for Nominatim responses without user choice is primarily a privacy/quality issue rather than a direct exploit path. It can still be problematic because it silently imposes locale behavior and may affect returned results or disclose linguistic/user-context assumptions that were not requested.

Missing User Warnings

High
Confidence
99% confidence
Finding
The file contains hardcoded fallback credentials, including a plaintext Earthdata username and password. Embedded secrets are highly dangerous because they can be extracted from source control, reused by anyone who obtains the code, and may grant unauthorized access to external data services or associated accounts.

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
94% 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
94% 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
94% 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
90% 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
93% 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
93% 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
92% 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
96% 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
96% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
def _resolve(name: str) -> str:
    """env > 用户 secrets > .netrc > 默认. 空字符串视为未设."""
    env_val = os.environ.get(name, "").strip()
    if env_val:
        return env_val
Confidence
89% 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
90% 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
89% 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
93% 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