Back to skill

Security audit

geoskill-3d-terrain-visualization

Security checks across malware telemetry and agentic risk

Overview

The main terrain renderer looks local, but the package includes under-disclosed credential and network helper code unrelated to that purpose, so it should go to Review.

Install only if you are comfortable with a package that, beyond the advertised offline terrain renderer, includes callable code for remote geocoding, downloads, and reading local credential stores. Prefer running only the documented main script in an isolated environment and avoid placing unrelated secrets in ~/.netrc or ~/.geoskill/secrets.json when using it.

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

Lp3

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding
The skill declares itself as an offline/local terrain renderer, yet the detected capabilities include network, shell, environment access, and unrestricted file read/write without corresponding permission disclosure. That gap is dangerous because it prevents users and reviewers from understanding the real attack surface, and those capabilities could be used to access local data, invoke external tools, or contact remote services unexpectedly.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This is a strong description-behavior mismatch: a terrain visualization skill reportedly contains geocoding, remote HTTP access, credential handling for multiple external services, and even hardcoded fallback credentials unrelated to its stated purpose. That combination materially increases risk because hidden network and credential features can enable data exfiltration, unauthorized third-party access, and supply-chain style abuse under the cover of a benign geospatial workflow.

Description-Behavior Mismatch

Medium
Confidence
83% confidence
Finding
The vendored metadata shows the skill bundles a 'landsat-download' component even though the declared skill purpose is 3D terrain visualization. This scope mismatch increases the attack surface by introducing download-related code and credential-handling functionality that may perform network access or process external data beyond user expectations, which is risky in a skill that should primarily render local terrain products.

Context-Inappropriate Capability

Medium
Confidence
86% confidence
Finding
The module persists user queries and resolved AOI data under the user's home directory by default, which can leak sensitive place searches over time to other local users, backups, or forensic inspection. While not a remote compromise vector, it creates an unnecessary privacy-sensitive artifact without explicit consent or retention controls.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The module is a broad credential aggregator for multiple external services, including OPENAI_API_KEY and unrelated data-provider accounts, despite the declared skill being a 3D terrain visualization tool. This unnecessarily expands the secret access surface of the skill and creates a path for over-privileged credential use if any downstream code imports this helper.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code is designed to discover credentials from ~/.geoskill/secrets.json and ~/.netrc in the user's home directory, which is sensitive local secret material. For a visualization-focused skill, automatic home-directory secret harvesting is an overreach and increases the chance that unrelated credentials are accessed and later misused or leaked by other code paths.

Missing User Warnings

Medium
Confidence
80% confidence
Finding
User-supplied place queries are sent to third-party geocoding services without any visible notice in this file, which can expose potentially sensitive location interests or operational targets to external providers. In a terrain-visualization skill, AOI inputs may plausibly be sensitive, so silent transmission increases privacy and compliance risk even if the transport is HTTPS.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The cache writes raw resolved-query data to a predictable path in the user's home directory without any visible warning, creating a local privacy leak and unnecessary persistence of location-related input. For geospatial workflows, searched places can be sensitive, so silent retention meaningfully increases exposure if the host is shared or later inspected.

Missing User Warnings

High
Confidence
99% confidence
Finding
The file contains hardcoded fallback credentials, including a concrete Earthdata username and password. Embedding live-looking credentials in source code is dangerous because they can be extracted by anyone with repository access, silently used in production when env vars are absent, and reused across environments without visibility.

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
95% 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
95% 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
95% 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
94% 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
94% 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
93% 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
97% 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
97% 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
96% 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
93% 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

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
92% 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
97% 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
98% confidence
Finding
secrets.json

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 兜底
    """
Confidence
94% 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