Back to skill

Security audit

Kb Keyword Graph

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a read-only keyword-graph helper, but its documentation and code expose broader local-file, Elasticsearch, and configurable network behaviors than the primary 2brain-only framing suggests.

Review this skill before installing. Use it only with a trusted 2brain API base and avoid setting TWOBRAIN_API_BASE to arbitrary or http URLs. Do not enable the local or Elasticsearch backends unless you intentionally want the agent to read that folder or query that ES endpoint. Treat ~/.config/2brain-keyword-map/config.json as a sensitive token file, and be cautious opening generated HTML graphs from untrusted keyword data until the renderer escapes content safely.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/kw_graph.py:34
Finding

Bearer Credential Can Be Sent to an Arbitrary Environment-Controlled Endpoint

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/kw_graph.py:228
Finding

Backend-Controlled Keywords Enable Stored Script Injection in Generated HTML Graphs

Content
View full analysis
{const t=sib.reduce((s,x)=>s+x.count,0);return t?n.count/t*100:null}; const label=p=>p===null?'—':p.toFixed(1)+'%'; const color=p=>{const q=Math.max(0,Math.min(100,p??0))/100;return 'hsl('+(205-200*q)+' 78% '+(52-5*q)+'%)'}; function at(n,p,a,r,kind,active,click){const x=Math.cos(a)*r,y=Math.sin(a)*r,s=.84+(p??0)/100*.28;return ''+n.keyword+''+label(p)+''} function ring(nodes,r,kind,pi){const m=nodes.length||1;return nodes.map((n,i)=>at(n,pct(n,nodes),i/m*Math.PI*2-Math.PI/2,r,kind,(kind==='l1'&&i===l1)||(kind==='l2'&&i===l2),[pi??i,kind==='l2'?i:null])).join('')} function render(){let h='
'+ring(data,270,'l1');if(l1!==null){const k=data[l1].children;h+=k.length?ring(k,155,'l2',l1):'
没有二级主题
';if(l2!==null&&k[l2]){const lv=k[l2].children;h+=lv.length?ring(lv,64,'l3',l1):'
没有三级主题
'}}app.innerHTML=h;sub.textContent=l1===null?'点一级主题展开二级;点二级展开三级。始终在同一张图内。':l2===null?'已展开二级;点一个二级主题,三级会在内圈出现。':'三级已展开;点任意一级可切换分支。';app.querySelectorAll('.node').forEach(b=>b.onclick=()=>{if(b.dataset.kind==='l1'){l1=+b.dataset.i;l2=null}else if(b.dataset.kind==='l2'){l1=+b.dataset.i;l2=+b.dataset.j}rende ...[truncated 2658 chars]
Remediation
View remediation
` element and parse its text content with `JSON.parse`. 5. Before embedding JSON into HTML, escape characters that are significant to the HTML parser, including `<`, `>`, `&`, U+2028, and U+2029. At minimum, encode `<` as `\u003c` so `` cannot terminate the element. 6. Alternatively, encode the JSON as Base64 and decode it in the page, while still using safe DOM construction for displayed values. 7. Add a restrictive Content Security Policy that blocks inline scripts and remote connections. This should be defense in depth rather than the primary fix. 8. Validate all keyword fields as strings with reasonable length limits to prevent malformed or excessively large graph artifacts. 9. Add regression tests using payloads such as: - `` - `` - Quotes and malformed tag sequences 10. Invalidate or regenerate previously cached graph data and HTML files after deploying the fix. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (30)

Tainted flow: 'req' from os.environ.get (line 82, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/kw_graph.py (reported line 97)May include surrounding context.

python
)
    print("… 正在向 2brain 拉取关键词树,请稍候", file=sys.stderr)
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            payload = json.loads(r.read())
    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", "replace")[:200]

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documented behavior extends beyond the stated 2brain-only scope to include local document directories and Elasticsearch, despite repeated claims that the skill does not route to local files or other sources. This kind of deceptive or inconsistent scoping is dangerous because operators may approve the skill under a narrower threat model than the one it actually implements.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documented behavior extends beyond the stated 2brain-only scope to include local document directories and Elasticsearch, despite repeated claims that the skill does not route to local files or other sources. This kind of deceptive or inconsistent scoping is dangerous because operators may approve the skill under a narrower threat model than the one it actually implements.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest framing says the skill only reads a 2brain KB by base_id, while the documentation later exposes unrelated local-folder and Elasticsearch backends that generate keyword trees from other corpora. This is a security-relevant integrity issue because downstream policy engines, reviewers, or users may rely on the manifest to understand the trust boundary and data exposure surface.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The documentation explicitly says the skill does not route to local files, but later describes a local backend that reads .txt/.md files from a folder and computes a tree. This contradiction can cause unanticipated local data exposure if the agent or user trusts the earlier statement and invokes the skill in environments containing sensitive files.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill manifest says the backend is currently 2brain-only and positions the tool as a read-only KB graph reader, but the code silently supports additional local and Elasticsearch backends. This creates undeclared data-access capability expansion: a caller or attacker controlling args/config can make the skill read local corpora or query external services outside the stated trust boundary, violating least privilege and user expectations.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill declares no explicit tool/permission scope even though the documentation shows use of environment variables, filesystem reads/writes, and outbound network access. In an agent setting, missing scope boundaries increases the chance the skill is invoked with broader privileges than users expect, especially because the trigger is broad and the skill later documents non-2brain backends.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad and include common requests like 'what's in this library' or 'take a look at this library', increasing the chance of accidental invocation. Because the skill can access network resources and, per later documentation, local files or Elasticsearch, unintended triggering materially increases exposure risk.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
79% confidence
Finding

The documentation recommends storing an API token persistently in ~/.config/2brain-keyword-map/config.json. Even with restrictive permissions, long-lived local credential storage increases the blast radius of host compromise or accidental reuse by other processes, and it conflicts somewhat with the narrow read-only positioning of the skill.

Content

Scanner excerpt · SKILL.md (reported line 41)May include surrounding context.

bash
# Option A: private config file (recommended — token stays out of env & artifacts)
mkdir -p ~/.config/2brain-keyword-map
cat > ~/.config/2brain-keyword-map/config.json <<'JSON'
{ "token": "2B-your-graph-API-key", "base_id": 700 }
JSON

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

One section says the current backend works by base_id and the agent should ask for a base_id, but other sections expose corpus-path and Elasticsearch parameter modes. This inconsistency weakens safe routing guarantees and may let the skill operate on unintended sources if the agent follows one section while the implementation supports broader behavior.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 137)May include surrounding context.

md
**Credential discipline (hard rule)**:
- The token is sent only as an `Authorization: Bearer` header to the fixed 2brain endpoint;
- **never** print the token to the conversation, write it into HTML/JSON artifacts, logs, or URL query;
- the engine guarantees artifacts contain no token; don't repeat the key when relaying results.

**Output discipline**:

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/SKILL.zh.md (reported line 34)May include surrounding context.

bash
# 方式一:私有配置文件(推荐,token 不进环境/不落产物)
mkdir -p ~/.config/2brain-keyword-map
cat > ~/.config/2brain-keyword-map/config.json <<'JSON'
{ "token": "2B-你的图谱APIKey", "base_id": 700 }
JSON

Session Persistence

Medium
Category
Rogue Agent
Confidence
74% confidence
Finding

The documentation instructs users to persist an API token in a plaintext config file under the home directory and also suggests environment variables as an alternative. While file permissions are restrictive, long-lived plaintext secret persistence increases the blast radius if the user account, backups, dotfiles, or local filesystem are later exposed; the skill context makes this somewhat less dangerous because the token is intended only for a read-only keyword-graph API, but it still grants access to backend data for the configured base.

Content

Scanner excerpt · references/validation.md (reported line 13)May include surrounding context.

md
# 1. 把 kb-keyword-graph/ 放进 Agent 的 skills 目录
#    OpenClaw: ~/.openclaw/<workspace>/skills/kb-keyword-graph/
# 2. 配置凭证(二选一)
mkdir -p ~/.config/2brain-keyword-map
printf '{ "token": "2B-你的图谱Key", "base_id": 700 }' > ~/.config/2brain-keyword-map/config.json
chmod 700 ~/.config/2brain-keyword-map && chmod 600 ~/.config/2brain-keyword-map/config.json
#    或: export TWOBRAIN_GRAPH_KEY=2B-... ; export TWOBRAIN_BASE_ID=700

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 45)May include surrounding context.

md
# 2. 配置凭证(二选一)
mkdir -p ~/.config/2brain-keyword-map
printf '{ "token": "2B-你的图谱Key", "base_id": 700 }' > ~/.config/2brain-keyword-map/config.json
chmod 700 ~/.config/2brain-keyword-map && chmod 600 ~/.config/2brain-keyword-map/config.json
#    或: export TWOBRAIN_GRAPH_KEY=2B-... ; export TWOBRAIN_BASE_ID=700
#    课程环境: export TWOBRAIN_API_BASE=https://test.2brain.ai/api
# 3. 自检

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/SKILL.zh.md (reported line 38)May include surrounding context.

md
# 2. 配置凭证(二选一)
mkdir -p ~/.config/2brain-keyword-map
printf '{ "token": "2B-你的图谱Key", "base_id": 700 }' > ~/.config/2brain-keyword-map/config.json
chmod 700 ~/.config/2brain-keyword-map && chmod 600 ~/.config/2brain-keyword-map/config.json
#    或: export TWOBRAIN_GRAPH_KEY=2B-... ; export TWOBRAIN_BASE_ID=700
#    课程环境: export TWOBRAIN_API_BASE=https://test.2brain.ai/api
# 3. 自检

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/validation.md (reported line 15)May include surrounding context.

md
# 2. 配置凭证(二选一)
mkdir -p ~/.config/2brain-keyword-map
printf '{ "token": "2B-你的图谱Key", "base_id": 700 }' > ~/.config/2brain-keyword-map/config.json
chmod 700 ~/.config/2brain-keyword-map && chmod 600 ~/.config/2brain-keyword-map/config.json
#    或: export TWOBRAIN_GRAPH_KEY=2B-... ; export TWOBRAIN_BASE_ID=700
#    课程环境: export TWOBRAIN_API_BASE=https://test.2brain.ai/api
# 3. 自检

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 45)May include surrounding context.

md
# 2. 配置凭证(二选一)
mkdir -p ~/.config/2brain-keyword-map
printf '{ "token": "2B-你的图谱Key", "base_id": 700 }' > ~/.config/2brain-keyword-map/config.json
chmod 700 ~/.config/2brain-keyword-map && chmod 600 ~/.config/2brain-keyword-map/config.json
#    或: export TWOBRAIN_GRAPH_KEY=2B-... ; export TWOBRAIN_BASE_ID=700
#    课程环境: export TWOBRAIN_API_BASE=https://test.2brain.ai/api
# 3. 自检

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/SKILL.zh.md (reported line 38)May include surrounding context.

md
# 2. 配置凭证(二选一)
mkdir -p ~/.config/2brain-keyword-map
printf '{ "token": "2B-你的图谱Key", "base_id": 700 }' > ~/.config/2brain-keyword-map/config.json
chmod 700 ~/.config/2brain-keyword-map && chmod 600 ~/.config/2brain-keyword-map/config.json
#    或: export TWOBRAIN_GRAPH_KEY=2B-... ; export TWOBRAIN_BASE_ID=700
#    课程环境: export TWOBRAIN_API_BASE=https://test.2brain.ai/api
# 3. 自检

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/validation.md (reported line 15)May include surrounding context.

md
# 2. 配置凭证(二选一)
mkdir -p ~/.config/2brain-keyword-map
printf '{ "token": "2B-你的图谱Key", "base_id": 700 }' > ~/.config/2brain-keyword-map/config.json
chmod 700 ~/.config/2brain-keyword-map && chmod 600 ~/.config/2brain-keyword-map/config.json
#    或: export TWOBRAIN_GRAPH_KEY=2B-... ; export TWOBRAIN_BASE_ID=700
#    课程环境: export TWOBRAIN_API_BASE=https://test.2brain.ai/api
# 3. 自检

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

该 markdown 文件适用 SQP-1。L29-L34 将“这个库里有什么”“知识结构是怎样的”“帮我看下”“这个库主要讲哪些主题”等常见自然表达直接定义为触发条件,且 L34 说明即使没说“图谱”也会触发,扩大了匹配范围。虽然文中提供了一个排歧说明,但整体仍缺少更明确的边界、负例或更具体的限定,容易与普通问答请求重叠。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file presents all operational guidance exclusively in Chinese, which effectively forces a specific language for users of the skill. The policy allows locale constraints only when the constraint is explicitly documented and justified or when users are offered a language choice, neither of which appears here.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code introduces undeclared local and elasticsearch backends even though the skill metadata says the current backend is 2brain-only and does not route to other sources. This creates a capability gap between declared behavior and actual behavior, which is dangerous because policy, review, and user trust may rely on the manifest while the code can access local files or external services.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The local backend can read arbitrary .txt/.md files from a caller-supplied directory via rglob, which expands the skill from KB inspection into general local file access. In an agent environment, this can expose sensitive data from unintended directories and bypass the read-only, KB-scoped expectations described in the skill context.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The Elasticsearch backend allows outbound HTTP requests to a configurable es_url, enabling the skill to query arbitrary external or internal ES instances beyond the declared 2brain source. This broadens the trust boundary and can be abused for unauthorized data access or SSRF-like probing of reachable services from the runtime environment.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code reads a local config file from the user's home directory and, together with later support for local corpus paths, expands the skill from a narrowly described remote KB graph reader into one that can inspect local resources. In context, this mismatch is dangerous because users invoking a knowledge-base visualization skill would not reasonably expect filesystem reads or arbitrary local corpus ingestion paths.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.