Back to skill

Security audit

CGArtLab Search

Security checks for vulnerabilities and agentic risk

Overview

This skill’s search requests, API-key handling, and optional Tencent integration fit its disclosed internet-search purpose.

Search terms go to the selected external providers, so omit confidential details. Configure only needed API keys and protect any secrets.json file. Review the optional Tencent installer before running it, and remember its key configuration persists across sessions.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (60)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CHANGELOG.md (reported line 27)May include surrounding context.

md
### Changed

- `SKILL.md`:`description` 去掉 “pending Tencent News/Zhihu”,路由表补 `tencent`(热点榜 / 中文新闻搜索)与 `zhihu`(中文全网)入口,Backend status 段改为 2026-10-20 实测结果。
- **`tencent` 的密钥归属特殊**:key 由 `tencent-news-cli apikey-set` 持久化到 CLI 自身配置(Windows 为 `HKCU\Environment`),**不读 `secrets.json`**;`TENCENT_NEWS_KEY` / `tencent_news_key` 两个槽位保留但未使用,文档已注明。

### Fixed

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CHANGELOG.md (reported line 40)May include surrounding context.

md
## [0.1.0] - 2026-10-02

> **一句话概括**:这是首次公开发布,一次性并入自内部初版以来的全部工作——9 个搜索后端、路由策略、双实现调度脚本、密钥管理与 8 条评测用例。**你不需要做任何事**;需要 `brave` / `exa` 的话另行填入 `secrets.json`(见 `secrets.example.json`)。

首次发布(此前未对外发布过任何版本,本次涵盖自内部初版以来的全部工作)。

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CHANGELOG.md (reported line 49)May include surrounding context.

md
- **9 个搜索后端**(`references/backends.md`):`bing`(cn.bing.com RSS 通用网页搜索)、`context7`(库/框架/API 文档两步检索)、`qqnews`(腾讯新闻热榜 JSON)、`hupu`(虎扑足球新闻列表)、`so`(Stack Overflow 问答)、`github`(仓库搜索)、`hn`(Hacker News)、`brave`(通用网页/新闻,需 key)、`exa`(深度语义检索,需 key)。前 7 个免密钥,可经 `web_fetch` 在受限出口环境使用。
- **路由策略**(`references/routing.md`):按意图分流的双列路由表(curl harness / DSH web_fetch),含查询改写规则(长时效句改关键词、紧复合形式重试)、数字与行情两步法、故障范围判定、诚实降级规则。
- **双实现调度脚本**:`scripts/search.mjs`(零依赖 Node ESM,11 个后端适配器,输出归一化 JSON)与 `scripts/search.sh`(curl + python3 等价实现)。
- **密钥管理**:`secrets.example.json` 模板 + `.gitignore` 屏蔽真实 `secrets.json`(实测 `git check-ignore` 命中);环境变量优先、文件回退。
- **实测记录**:`web_fetch` 主机可达性地图(区分可达 / JS 截断 / 不可达三类)、知乎 API 403 反爬、Bing `site:` 兜底在中文长句下坍缩为词条定义等实证案例。
- **评测用例**:`evals/evals.json` 8 条(文档检索、热点新闻、足球新闻、知乎降级诚实性、数据两步法、跨域广研等)。
- **仓库治理**:`.gitattributes`(LF 归一)、`LICENSE`(CC BY-NC-SA 4.0)、`docs/RELEASING.md`(发布流程与三道闸)、`CHANGELOG.md` 本文件。

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · docs/POSTMORTEM-0.1.0.md (reported line 14)May include surrounding context.

md
| 8 条评测用例 | 解析 `evals/evals.json` | ✅ 实际 8 条(id 1–8,名称逐条核对) |
| 11 个后端适配器 | 解析 `search.mjs` 的 `ADAPTERS` 与函数定义 | ✅ 恰好 11 个,且两处集合完全一致 |
| CHANGELOG 的后端名都真实存在 | 比对 CHANGELOG 提到的名字与 `references/backends.md` 的二级小节 | ✅ 11 个名字(含 tencent/zhihu 两个待配置项)全部有对应小节 |
| `secrets.json` 从未进历史 | `git rev-list --all --objects` + 遍历对象库**全部 15 个 blob** 搜 API Key 明文 | ✅ 0 命中;索引里也没有该文件 |
| LICENSE 是 CC BY-NC-SA 4.0 且无他家署名 | 读首行、查 CC/4.0 关键字、搜 attention/cgartlab/quill 残留 | ✅ 首行为官方 4.0 International 标题,**无任何他项目名残留** |
| 安装与仓库一致 | 14 个文件 MD5 逐一比对 + 目录差集 | ✅ 0 问题;安装目录**无多余文件、无缺失** |
| 安装的 frontmatter 合法 | 结构检查(`---` 包裹、五个键齐全、`version` 二空格缩进) | ✅ 全部通过;键顺序与 `attention`/`quill` 两个**已知可加载**的技能**完全一致** |

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/backends.md (reported line 41)May include surrounding context.

md
Load order: environment variables, then `secrets.json` next to SKILL.md.

| Env var | secrets.json field |
|---|---|
| BRAVE_SEARCH_API_KEY | brave_api_key |
| EXA_API_KEY | exa_api_key |

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/backends.md (reported line 49)May include surrounding context.

md
| ZHIHU_API_KEY | zhihu_api_key |

Key-less backends (bing, context7, qqnews, hupu, so, github, hn) need NO secrets.
Never hardcode keys into requests you log or into git. `secrets.json` is gitignored.

> **`tencent` is the exception**: its key is owned by the `tencent-news-cli` binary
> (`tencent-news-cli apikey-set`), not by `secrets.json`. The `TENCENT_NEWS_KEY` /

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/backends.md (reported line 52)May include surrounding context.

md
Never hardcode keys into requests you log or into git. `secrets.json` is gitignored.

> **`tencent` is the exception**: its key is owned by the `tencent-news-cli` binary
> (`tencent-news-cli apikey-set`), not by `secrets.json`. The `TENCENT_NEWS_KEY` /
> `tencent_news_key` slots are unused — set the key through the CLI instead.

## Runtime prerequisites for the two scripts

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/backends.md (reported line 308)May include surrounding context.

md
Because it is persisted (registry on Windows, shell RC on macOS/Linux), a terminal that was
already open will not see it — set `TENCENT_NEWS_APIKEY` in the current process, or open a new
one. The adapter does **not** read `secrets.json` for this backend.

### Commands used

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/gate.sh (reported line 45)May include surrounding context.

sh
'; then ok "metadata.version 存在"; else no "metadata.version 缺失"; fi

echo "[4/5] 密钥不入库"
if git ls-files --error-unmatch secrets.json >/dev/null 2>&1; then
  no "secrets.json 被 git 跟踪了"
else
  ok "secrets.json 未被跟踪"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/gate.sh (reported line 46)May include surrounding context.

sh
echo "[4/5] 密钥不入库"
if git ls-files --error-unmatch secrets.json >/dev/null 2>&1; then
  no "secrets.json 被 git 跟踪了"
else
  ok "secrets.json 未被跟踪"
fi

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/gate.sh (reported line 48)May include surrounding context.

sh
if git ls-files --error-unmatch secrets.json >/dev/null 2>&1; then
  no "secrets.json 被 git 跟踪了"
else
  ok "secrets.json 未被跟踪"
fi
if "$py" -c '
import json,sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/search.mjs (reported line 11)May include surrounding context.

js
//   backends: comma list from brave,exa,context7,tencent,zhihu,bing,qqnews,hupu,so,github,hn
//
// Keyed backends read env vars BRAVE_SEARCH_API_KEY EXA_API_KEY CONTEXT7_API_KEY
// TENCENT_NEWS_KEY ZHIHU_API_KEY (fallback: secrets.json next to SKILL.md).
// Key-less backends (bing,context7,qqnews,hupu,so,github,hn) need nothing.
// Output: one line of normalized JSON on stdout. Exit 0 if any backend returned results.
import { readFileSync } from 'node:fs';

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/search.sh (reported line 7)May include surrounding context.

sh
#
# Usage: ./search.sh <backend> "<query>" [limit]
#   backend: brave|exa|context7|tencent|zhihu|bing|qqnews|hupu|so|github|hn
# Keys: env vars, or secrets.json next to SKILL.md (key-less backends need none).
# Output: one line of normalized JSON on stdout.
set -euo pipefail
b="${1:-}"; q="${2:-}"; n="${3:-5}"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/search.sh (reported line 29)May include surrounding context.

sh
echo '{"errors":[{"backend":"*","error":"no working python3/python found — set PYTHON=/path/to/python"}]}'; exit 0
fi

# secrets.json lives next to SKILL.md (skill root); a copy beside this script still works.
secrets_file=""
for cand in "$here/secrets.json" "$here/../secrets.json"; do
  [ -f "$cand" ] && secrets_file="$cand" && break

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CHANGELOG.md (reported line 35)May include surrounding context.

md
- **`tencent "关键词" --news` 丢弃关键词**:原逻辑把 `--news` 映射到 `hot`(热点榜),带关键词查询会返回与查询无关的头条。现仅当关键词为空时走 `hot`;`--news` 不再改变检索方式(该后端结果本就全是 `type=news`)。`references/backends.md` 的映射表同步更正。
- **`scripts/search.sh` 的 `tencent` / `zhihu` 仍是 “not configured” 占位**,与 `search.mjs` 不一致:按同一规格补齐实现(zhihu 走 `/content/global_search`,`Count` 本地截断 1-20;tencent 调官方 CLI,`--limit` 截断 1-50,含无关键词热点榜)。
- **`search.sh` 在本机全后端静默返回空**:脚本一律调 `python3`,而 Windows 上该命令可能是 Microsoft Store 别名存根(exit 0、无输出)。现探测 `$PYTHON` → `python3` → `python` 并**验证真实输出**(`print(1)` 必须等于 `1`),无可用解释器时输出明确错误。
- **`search.sh` 读不到 `secrets.json`**:路径以 MSYS 形式(`/d/...`)传给 Windows 原生 Python,触发 `FileNotFoundError`。改为经 **stdin** 传入 JSON;同时去掉 `shlex.quote`——它会把字面单引号塞进 `Authorization` 等请求头。
- **`zhihu` / `so` 的时间戳弃用告警**:`datetime.utcfromtimestamp` 在 Python 3.14 已弃用并往 stderr 打 `DeprecationWarning`;改为 timezone-aware,输出与 `search.mjs` 一致的 `...Z` 形式。

## [0.1.0] - 2026-10-02

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CHANGELOG.md (reported line 66)May include surrounding context.

md
skill 可能因此不被加载。对照组 `attention`/`quill` 的 frontmatter 两解析器均通过。
  现改为单引号标量(值内撇号双写),解析后内容与修复前逐字一致(815 字符)。

- **`secrets.json` 解析路径错误**(`scripts/search.mjs` 与 `scripts/search.sh`):文件实际位于技能根目录(`SKILL.md` 旁,与 `references/backends.md` 的说明一致),但两个脚本都在 `scripts/` 子目录下查找,导致 `brave` / `exa` / `context7` / `tencent` / `zhihu` 等需密钥的后端永远返回 `missing key`(异常被静默吞掉,退化为仅环境变量模式)。现改为按 `scripts/secrets.json` → `../secrets.json` 顺序探测,两个位置均可,环境变量优先级不变。免密钥后端不受影响。

**已知限制**(详见 `references/backends.md` 的可达性地图;不单列非标准章节)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CHANGELOG.md (reported line 66)May include surrounding context.

md
skill 可能因此不被加载。对照组 `attention`/`quill` 的 frontmatter 两解析器均通过。
  现改为单引号标量(值内撇号双写),解析后内容与修复前逐字一致(815 字符)。

- **`secrets.json` 解析路径错误**(`scripts/search.mjs` 与 `scripts/search.sh`):文件实际位于技能根目录(`SKILL.md` 旁,与 `references/backends.md` 的说明一致),但两个脚本都在 `scripts/` 子目录下查找,导致 `brave` / `exa` / `context7` / `tencent` / `zhihu` 等需密钥的后端永远返回 `missing key`(异常被静默吞掉,退化为仅环境变量模式)。现改为按 `scripts/secrets.json` → `../secrets.json` 顺序探测,两个位置均可,环境变量优先级不变。免密钥后端不受影响。

**已知限制**(详见 `references/backends.md` 的可达性地图;不单列非标准章节)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CHANGELOG.md (reported line 66)May include surrounding context.

md
skill 可能因此不被加载。对照组 `attention`/`quill` 的 frontmatter 两解析器均通过。
  现改为单引号标量(值内撇号双写),解析后内容与修复前逐字一致(815 字符)。

- **`secrets.json` 解析路径错误**(`scripts/search.mjs` 与 `scripts/search.sh`):文件实际位于技能根目录(`SKILL.md` 旁,与 `references/backends.md` 的说明一致),但两个脚本都在 `scripts/` 子目录下查找,导致 `brave` / `exa` / `context7` / `tencent` / `zhihu` 等需密钥的后端永远返回 `missing key`(异常被静默吞掉,退化为仅环境变量模式)。现改为按 `scripts/secrets.json` → `../secrets.json` 顺序探测,两个位置均可,环境变量优先级不变。免密钥后端不受影响。

**已知限制**(详见 `references/backends.md` 的可达性地图;不单列非标准章节)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · LESSONS.md (reported line 24)May include surrounding context.

md
## 脚本与密钥

### secrets.json 解析路径
- 失误:`secrets.json` 解析路径未从技能根目录查找,在不同 harness 下找不到文件 → 规则:解析路径改为技能根优先(commit 1ad5fb8)

### key-less vs keyed 后端

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 48)May include surrounding context.

md
Key-less backends need nothing. For brave/exa/tencent/zhihu set env vars
(`BRAVE_SEARCH_API_KEY`, `EXA_API_KEY`, `TENCENT_NEWS_KEY`, `ZHIHU_API_KEY`) or place a
`secrets.json` next to SKILL.md (see `secrets.example.json`). `secrets.json` is gitignored.

## Usage

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 48)May include surrounding context.

md
Key-less backends need nothing. For brave/exa/tencent/zhihu set env vars
(`BRAVE_SEARCH_API_KEY`, `EXA_API_KEY`, `TENCENT_NEWS_KEY`, `ZHIHU_API_KEY`) or place a
`secrets.json` next to SKILL.md (see `secrets.example.json`). `secrets.json` is gitignored.

## Usage

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/backends.md (reported line 39)May include surrounding context.

md
## Secrets (keyed backends only)

Load order: environment variables, then `secrets.json` next to SKILL.md.

| Env var | secrets.json field |
|---|---|

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/search.mjs (reported line 34)May include surrounding context.

js
const FILE_KEYS = { brave: 'brave_api_key', exa: 'exa_api_key', context7: 'context7_api_key', tencent: 'tencent_news_key', zhihu: 'zhihu_api_key' };
const secrets = {};
for (const b of Object.keys(ENV_KEYS)) { const v = process.env[ENV_KEYS[b]]; if (v) secrets[b] = v; }
// secrets.json lives next to SKILL.md (skill root); a copy beside this script still works.
const SECRETS_CANDIDATES = [join(here, 'secrets.json'), join(here, '..', 'secrets.json')];
for (const p of SECRETS_CANDIDATES) {
  try {

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/search.mjs (reported line 35)May include surrounding context.

js
const secrets = {};
for (const b of Object.keys(ENV_KEYS)) { const v = process.env[ENV_KEYS[b]]; if (v) secrets[b] = v; }
// secrets.json lives next to SKILL.md (skill root); a copy beside this script still works.
const SECRETS_CANDIDATES = [join(here, 'secrets.json'), join(here, '..', 'secrets.json')];
for (const p of SECRETS_CANDIDATES) {
  try {
    const f = JSON.parse(readFileSync(p, 'utf8'));

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/search.mjs (reported line 35)May include surrounding context.

js
const secrets = {};
for (const b of Object.keys(ENV_KEYS)) { const v = process.env[ENV_KEYS[b]]; if (v) secrets[b] = v; }
// secrets.json lives next to SKILL.md (skill root); a copy beside this script still works.
const SECRETS_CANDIDATES = [join(here, 'secrets.json'), join(here, '..', 'secrets.json')];
for (const p of SECRETS_CANDIDATES) {
  try {
    const f = JSON.parse(readFileSync(p, 'utf8'));

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/search.mjs:190

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/search.mjs:33