Back to skill

Security audit

geoskill-invasive-species-spread

Security checks across malware telemetry and agentic risk

Overview

The main invasive-species tool looks local, but the package also includes undisclosed helpers that can read credentials and contact outside services.

Review this package before installing. Running the documented main script for local or synthetic analysis appears aligned with the stated purpose, but the package contains extra helper code that can access local credential stores and external geocoding services if invoked. Avoid placing sensitive credentials in ~/.netrc or ~/.geoskill/secrets.json in environments where this skill may be used unless you trust the full package contents.

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

Lp3

Medium
Category
MCP Least Privilege
Confidence
78% confidence
Finding
The skill documentation declares no permissions and presents the tool as offline/local, yet the detected capabilities include environment access, file read/write, shell, and network. This mismatch can cause reviewers and users to grant trust under false assumptions, increasing the chance that local files, secrets, or system resources are accessed unexpectedly during execution.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This is a serious description-behavior mismatch: the skill claims to run fully offline for local geospatial analysis, but static analysis indicates remote-service access, secret loading from environment and user config files, and even embedded default credentials. In this context, hidden network activity and credential handling are especially dangerous because users may supply sensitive local datasets believing no data leaves the machine, while the code may also expose or misuse stored secrets.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
The AOI helper sends user-supplied place names to third-party geocoding services and also supports persistent caching under the user's home directory, which extends behavior beyond the stated invasive-species analysis function. This creates avoidable data disclosure and local data retention risks, especially when place names may reveal sensitive study locations, field sites, or operational targets.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
This file includes outbound network capability to external geocoding providers even though the skill's primary purpose is geospatial spread analysis, not network-backed lookup. In practice, that broadens the trust boundary and can leak user queries or enable unexpected external dependencies in environments where offline or privacy-preserving operation is expected.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
This credential manager exposes accessors for multiple unrelated third-party credentials, including OpenAI, CMA, FIRMS, and EOG, even though the skill is scoped to invasive-species GeoTIFF analysis. Broad credential plumbing increases the blast radius: any code path in the skill or shared core can obtain secrets beyond what this skill should need, violating least privilege and enabling unnecessary secret access if the skill is compromised or behaves unexpectedly.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code reads a user-level secrets file and can load broad credentials into process memory from a shared location in the user's home directory. In the context of a narrowly scoped geospatial skill, automatically ingesting unrelated secrets from ~/.geoskill/secrets.json materially increases the risk of over-collection and secret exposure if any downstream code logs, transmits, or misuses the resolved values.

Intent-Code Divergence

Low
Confidence
89% confidence
Finding
The docstring says passwords are not cached, but load_user_secrets() copies secrets into the module-level _DEFAULTS dict and reuses them across calls. This mismatch is security-relevant because operators may rely on the documented non-caching behavior when assessing exposure in long-lived processes, while secrets actually persist in memory longer than stated.

Context-Inappropriate Capability

Medium
Confidence
81% confidence
Finding
The file sends user-provided place queries to third-party geocoding services (Open-Meteo and optionally Nominatim), which can disclose sensitive locations, project targets, or operational interests outside the local execution boundary. This is especially relevant because the skill description focuses on ecological raster analysis, so unexpected outbound requests increase privacy and supply-chain exposure if users assume offline or self-contained processing.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Place queries are transmitted to external services without any warning or consent mechanism in this module. Even if the data seems low sensitivity, location queries can disclose research interests, protected habitats, biosecurity incidents, or proprietary survey areas to third parties.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
Resolved location data is persisted to a cache file in the user's home directory without disclosure or retention controls. This can leave a durable record of potentially sensitive locations on shared systems, containers, or analyst workstations, exposing operational or ecological study targets to other local users or later compromise.

Natural-Language Policy Violations

Medium
Confidence
76% confidence
Finding
Forcing the Accept-Language header to zh-CN without user consent can leak locale assumptions and alter returned results in ways the user did not request. While not a severe security issue on its own, it is an unnecessary privacy and behavior-affecting network parameter that may surprise users and make results less predictable.

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
93% 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
93% 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
93% 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
89% 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
92% 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
92% 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
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
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
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
93% 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
91% confidence
Finding
.netrc

Credential Access

High
Category
Privilege Escalation
Content
解析顺序:
    1. env: EARTHDATA_TOKEN
    2. ~/.geoskill/secrets.json
    3. .netrc: machine urs.earthdata.nasa.gov account <TOKEN>
    4. _DEFAULTS(通常为空)
    """
    return _resolve("EARTHDATA_TOKEN")
Confidence
88% 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
95% 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