Back to skill

Security audit

geoskill-orchard-tree-counting

Security checks across malware telemetry and agentic risk

Overview

The main tree-counting command is local, but the package also ships under-disclosed network, credential-reading, cache, and hardcoded credential code that does not fit the stated offline orchard-counting purpose.

Review this package before installing. The tree-counting script itself appears local, but the bundled core should be reduced or separated: remove the hardcoded Earthdata credentials, rotate that account if real, delete or isolate unused credential/download/geocoding modules, and disclose or disable any network geocoding and home-directory cache behavior. Run it in a restricted environment if you only need the synthetic or local CHM workflow.

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

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill declares no permissions, yet the analyzed capability set includes environment access, file read/write, network, and shell execution. This creates a transparency and trust problem: users may run a seemingly local geospatial skill without understanding it can access sensitive local data, invoke commands, or communicate externally.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented purpose is narrow and offline-oriented, but the broader implementation reportedly includes geocoding, remote downloads, credential handling for multiple services, and even embedded fallback Earthdata credentials. That mismatch is dangerous because it can conceal unexpected data exfiltration paths, expanded attack surface, and secret exposure in a skill that users would reasonably expect to be a local orchard-analysis tool.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The vendored metadata declares a different skill name ('landsat-download') than the advertised orchard tree counting skill, which indicates a supply-chain or packaging integrity problem. Even though this file is only metadata, a mismatch like this can hide accidental inclusion of unrelated code or dependencies, causing reviewers and operators to trust a package whose contents do not match its stated purpose.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The module sends user-supplied place queries to external geocoding services, which can leak user inputs and workflow context to third parties without any consent or clear disclosure in this file. In an offline-first orchard-counting skill, silent network egress expands the trust boundary and may violate user expectations or deployment restrictions.

Context-Inappropriate Capability

Medium
Confidence
85% confidence
Finding
The code stores cache data under the user's home directory, persisting queried places and resolved AOIs beyond the current run. That can expose sensitive location interests or operational context to other local users, backups, or later processes, especially when users do not expect disk writes from this skill.

Context-Inappropriate Capability

High
Confidence
89% confidence
Finding
The credential manager exposes access paths for multiple external services (FIRMS, CMA, OpenAI, EOG) that are unrelated to the declared orchard tree counting purpose. This unnecessarily broadens the skill’s access to user secrets and creates a larger attack surface for credential harvesting or later misuse, especially because the module is designed to read from environment variables and user-level secret stores.

Context-Inappropriate Capability

Medium
Confidence
83% confidence
Finding
The code loads user-level secrets from ~/.geoskill/secrets.json and merges them into runtime defaults for all known credential names, including services unrelated to orchard counting. Even without immediate exfiltration in this file, centralizing broad secret access inside a narrowly scoped skill violates least privilege and makes future misuse or accidental disclosure easier.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
This file implements networked place/geocoding resolution that is materially outside the stated purpose of an orchard tree-counting skill. In an agent context, mismatched capabilities increase attack surface by enabling unexpected outbound requests, location handling, and data flows that users and reviewers would not anticipate from the manifest, which can lead to privacy leakage and policy circumvention.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The code makes external HTTP requests to Open-Meteo and Nominatim, sending user-supplied place names to third parties. For a tree-counting skill, this is an unjustified capability because it creates unnecessary exfiltration and reliability risk, especially if the place input contains sensitive project names, farm identifiers, or user-provided locations.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
Outbound geocoding requests transmit user-provided place names to third-party services without any visible warning or consent mechanism in this module. Even if the data is only a place string, it may reveal sensitive project locations, client names, or areas of interest and is therefore a real privacy/security concern.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The cache write path persists resolved query data to disk without user-facing disclosure, creating a local privacy leak and an audit trail of searched places. In geospatial workflows, such place queries can be operationally sensitive, so silent persistence is more dangerous than ordinary app caching.

Missing User Warnings

High
Confidence
99% confidence
Finding
The module contains hardcoded fallback Earthdata credentials in source code, including a plaintext password. Embedded credentials are highly dangerous because anyone with repository access, package access, logs, or source distribution can recover and reuse them, and the orchard-counting context does not justify shipping 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
82% 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
82% 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
82% 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
80% 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
81% 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
81% 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(name: str) -> str:
    """env > 用户 secrets > .netrc > 默认. 空字符串视为未设."""
    env_val = os.environ.get(name, "").strip()
    if env_val:
        return env_val
Confidence
78% 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
84% 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
77% confidence
Finding
.netrc

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