安全决策报告

forest-carbon-estimate

技能功能合法(森林碳储量估算),但存在硬编码密码违反最佳实践、凭证系统理论上面可被滥用于外传但实际未被调用、文档声称纯本地处理但代码有网络依赖等问题,均属轻微瑕疵,不影响整体安全。

安装决策优先 来源: ClawHub 扫描时间: 2026/7/27
文件 20
IOC 15
越权项 2
发现 5

为什么得出这个结论

1/4 个维度触发
阻止
声明与实际能力

发现 2 项声明之外的能力或越权行为。

复核
隐藏执行与外联

提取到 15 个一般风险产物,需要结合上下文判断。

通过
攻击链与高危发现

没有形成明确的恶意路径。

通过
依赖与供应链卫生

依赖结构存在,但暂未看到明显高危告警。

风险分是怎么被拉高的

源代码中硬编码 NASA Earthdata 默认密码 +15

_geoskill_core/credentials.py:_DEFAULTS 字典包含明文用户名 'ruiduobao' 和密码 'Ruiduobao123',违反源码安全最佳实践

凭证系统设计可被滥用(影子功能) +5

credentials.py 提供了完整的凭证解析链(env→secrets.json→.netrc→默认值),理论上可被恶意修改调用 get_openai_key() 等函数外传凭证,但当前 skill 代码未调用任何凭证获取函数

SKILL.md 声明与实际行为轻微不符 +5

Privacy Disclosure 声称'无数据发送到任何服务器',但代码依赖 Open-Meteo 和 Nominatim 在线 geocoding(aoi.py);_resolve_place 依赖不存在的外部 _shared/place_resolver.py

最关键的证据

低危 供应链

硬编码明文默认密码

_geoskill_core/credentials.py 第 68-70 行定义了 _DEFAULTS 字典,包含明文 NASA Earthdata 用户名 'ruiduobao' 和密码 'Ruiduobao123'。虽然设计文档声称'这些值通过 helper 间接使用,不应出现在 skill 源码/日志/文档/报告里',但它们仍然是可读的 Python 模块级常量,且该模块已被 vendoring 到当前 skill。若此文件被意外 import 且环境变量均未设置,会 fallback 到这些硬编码值(仅被 _resolve() 使用,当前 skill 未调用)。

_geoskill_core/credentials.py:68
将默认密码改为空字符串或占位符,强制用户通过环境变量或 secrets.json 提供真实凭证
提示 文档欺骗

Privacy Disclosure 声明与实际网络行为轻微不符

SKILL.md 第 10-11 行声明'This tool processes data locally. No data is sent to any server.'。但 scripts/forest-carbon-estimate.py 的 _resolve_place() 和 from-canopy-height 命令会通过 _geoskill_core/aoi.py 发起对 https://geocoding-api.open-meteo.com 和 https://nominatim.openstreetmap.org 的 HTTP 请求,用于地名解析。这是实现合理功能所必需的,但未在文档中声明。

SKILL.md:10
在 SKILL.md 的 Privacy Disclosure 或 Troubleshooting 节明确列出所需网络端点(Open-Meteo geocoding API、Nominatim)
提示 文档欺骗

_resolve_place 依赖不存在的外部模块

scripts/forest-carbon-estimate.py 的 _resolve_place() 函数(行 27-43)尝试从 '../_shared/place_resolver.py' 或 './_shared/place_resolver.py' 加载 place_resolver 模块。该路径不存在于当前 skill,调用会抛出 ValueError。这是未 vendoring 的外部依赖,SKILL.md 也未提及此功能的前置条件。

scripts/forest-carbon-estimate.py:27
正式将 place_resolver.py vendoring 到 _geoskill_core,或在 SKILL.md 中声明此为 Phase 0 DISABLED 功能
提示 代码执行

cmd_from_canopy_height 的 importlib 代码块永不可达

scripts/forest-carbon-estimate.py 的 cmd_from_canopy_height 函数在 'return 0' 之后(行 ~350+)有一段通过 importlib.util.spec_from_file_location 加载外部 from_stac.py 的代码块。由于前面的 'return 0' 语句在所有正常执行路径上都会退出函数,这段代码在任何条件下都不会执行,构成死代码。

scripts/forest-carbon-estimate.py:340
删除死代码或重构为有效逻辑
提示 敏感访问

credentials.py 支持读取 ~/.netrc 和 ~/.geoskill/secrets.json

_geoskill_core/credentials.py 的 _read_netrc() 和 load_user_secrets() 函数会读取用户 home 目录下的 .netrc 和 ~/.geoskill/secrets.json 文件。虽然这是合法的凭证管理模式,但 SKILL.md 未声明此能力,且当前 skill 代码本身并未调用这些凭证获取函数——它们只是被 vendoring 进来而未被使用。

_geoskill_core/credentials.py:106
如果当前 skill 不需要这些凭证功能,不必将整个 credentials.py 模块 vendoring 进来

声明能力 vs 实际能力

文件系统 通过
声明 READ
→
推断 WRITE
scripts/forest-carbon-estimate.py:process_raster 读写 GeoTIFF;write_raster 写输出文件,声明中'本地处理'与之一致
网络访问 阻止
声明 NONE
→
推断 READ
_geoskill_core/aoi.py:_open_meteo_search/_nominatim_search 发起 HTTP 请求到外部 API,但 SKILL.md 未声明
环境变量 阻止
声明 NONE
→
推断 READ
_geoskill_core/credentials.py:_resolve() 通过 os.environ.get 读取环境变量,但 SKILL.md 和主脚本均未声明
命令执行 通过
声明 NONE
→
推断 NONE
未发现 subprocess / shell=True / os.system 等 shell 执行调用

可疑产物与外联

中危 外部 URL
https://www.globalforestwatch.org/

README.md:183

中危 外部 URL
https://gedi.umd.edu/

README.md:184

中危 外部 URL
https://www.ipcc-nggip.iges.or.jp/public/2006gl/

README.md:203

中危 外部 URL
https://www.ipcc-nggip.iges.or.jp/public/2019rf/

README.md:210

中危 外部 URL
https://clawhub.ai

_geoskill_core/aoi.py:99

中危 外部 URL
https://geocoding-api.open-meteo.com/v1/search

_geoskill_core/aoi.py:234

中危 外部 URL
https://nominatim.openstreetmap.org/search

_geoskill_core/aoi.py:272

中危 外部 URL
https://urs.earthdata.nasa.gov/users/new/

_geoskill_core/credentials.py:302

中危 外部 URL
https://urs.earthdata.nasa.gov/profile

_geoskill_core/credentials.py:306

中危 外部 URL
https://firms.modaps.eosdis.nasa.gov/api/map_key/

_geoskill_core/credentials.py:308

中危 外部 URL
http://data.cma.cn/

_geoskill_core/credentials.py:310

中危 外部 URL
https://eogdata.mines.edu/register/

_geoskill_core/credentials.py:314

依赖与供应链

包名版本来源漏洞备注
numpy >=1.21.0 pip 否 无上限锁定
rasterio >=1.3.0 pip 否 无上限锁定

文件构成

20 个文件 · 4378 行
Python 11 个文件 · 3395 行Markdown 5 个文件 · 945 行Other 1 个文件 · 21 行Text 2 个文件 · 14 行YAML 1 个文件 · 3 行
需关注文件 · 5
_geoskill_core/credentials.py Python · 317 行
硬编码明文默认密码 · credentials.py 支持读取 ~/.netrc 和 ~/.geoskill/secrets.json · https://urs.earthdata.nasa.gov/users/new/ · https://urs.earthdata.nasa.gov/profile · https://firms.modaps.eosdis.nasa.gov/api/map_key/ · http://data.cma.cn/ · https://eogdata.mines.edu/register/
scripts/forest-carbon-estimate.py Python · 1035 行
_resolve_place 依赖不存在的外部模块 · cmd_from_canopy_height 的 importlib 代码块永不可达 · https://planetarycomputer.microsoft.com/stac
_geoskill_core/aoi.py Python · 507 行
https://clawhub.ai · https://geocoding-api.open-meteo.com/v1/search · https://nominatim.openstreetmap.org/search
README.md Markdown · 343 行
https://www.globalforestwatch.org/ · https://gedi.umd.edu/ · https://www.ipcc-nggip.iges.or.jp/public/2006gl/ · https://www.ipcc-nggip.iges.or.jp/public/2019rf/
SKILL.md Markdown · 343 行
Privacy Disclosure 声明与实际网络行为轻微不符
其他文件 · sensors.py · test_forest-carbon-estimate.py · manifest.py · safe_download.py · checks.py · details.md +1

安全亮点

无恶意行为:无 base64 解码、eval()、subprocess / shell 执行、反向 shell 或 C2 通信
无凭证外传:虽然 credentials.py 提供了凭证获取接口,但当前 skill 代码中没有任何调用点主动外传凭证
依赖已版本锁定:requirements.txt 明确指定 numpy>=1.21.0, rasterio>=1.3.0
网络请求仅限合法公共服务:Open-Meteo geocoding API 和 Nominatim,无裸 IP 请求
文件写入限于输出目录:GeoTIFF/CSV 输出由用户指定路径,无遍历敏感路径行为
代码结构清晰:_geoskill_core 各模块职责明确(aoi/safe_download/manifest/errors/credentials)