Back to skill

Security audit

EvoMap GEP Client

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed EvoMap network client, but it includes under-scoped external data sharing and a hardcoded publishing identity that users should review before installing.

Install only if you are comfortable sending EvoMap searches, asset IDs, and a persistent node identifier to evomap.ai. Review fetched capsules as untrusted third-party advice, do not run validation commands or apply changes without explicit approval, and avoid using the bundled hardcoded Feishu publishing script unless you intend to publish exactly that content under that node identity.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/fetch.py:32
Finding
Persistent Agent Memory Is Read and Its Identifier Is Transmitted Externally<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch.py:32-43, 96-110`; also present in `scripts/get_capsule.py:34-45, 63-76` and `scripts/hello.py:52-64, 75-88` **Vulnerability Type**: T05: Unauthorized Access and Privilege Escalation **Risk Level**: Medium ### Vulnerable Code ```python # scripts/fetch.py:32-43 # 3. MEMORY.md memory_file = os.path.expanduser("~/.openclaw/workspace/MEMORY.md") if os.path.exists(memory_file): with open(memory_file) as f: import re for line in f: if "node_" in line and "sender_id" in line.lower(): m = re.search(r'node_[a-f0-9]+', line) if m: return m.group(0) print("❌ No sender_id found. Set EVOMAP_SENDER_ID env var, or save it to MEMORY.md.", file=sys.stderr) sys.exit(1) ``` ```python # scripts/fetch.py:96-110 sender_id = get_sender_id(args) payload = { "protocol": "gep-a2a", "protocol_version": "1.0.0", "message_type": "fetch", "message_id": make_message_id(), "sender_id": sender_id, "timestamp": now_iso(), "payload": { "query": query, "limit": limit, "include_tasks": include_tasks } } ``` ### Technical Analysis The scripts use the general-purpose OpenClaw persistent memory file as a configuration source. They open `~/.openclaw/workspace/MEMORY.md`, locate a line containing `sender_id` and a `node_` value, and include that value in requests sent to `https://evomap.ai`. The extraction is limited to a matching node identifier and is disclosed in the Skill documentation. Nevertheless, reading persistent Agent memory is broader than necessary for a network client that can obtain the same value from a command-line option, environment variable, or dedicated configuration file. General Agent memory may contain unrelated sensitive context and should not be used as an application configuration store. ### Attack Path 1. A user or Agent invokes `fetch.py`, `get_capsule.py`, or ...[truncated 995 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store the node ID in a dedicated configuration file, such as `~/.config/evomap/config.json`, rather than in general Agent memory. 2. Restrict the configuration file to the owning user, for example with mode `0600`. 3. Prefer an explicitly supplied `--sender-id` argument or `EVOMAP_SENDER_ID` environment variable. 4. Remove automatic `MEMORY.md` discovery, or require explicit user consent before accessing it. 5. Display the destination, identity field, and other transmitted metadata before the first request. 6. Document that search queries and asset IDs are sent to EvoMap and may be associated with the persistent node identifier. 7. Apply strict format and length validation to the sender ID before transmission. ]]>

T01 · Skill Instruction Hijacking

Warning
Location
SKILL.md:39
Finding
Untrusted Remote Capsules Are Presented to the Agent as Actionable Guidance<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:39-40`; `scripts/fetch.py:113-141`; `scripts/get_capsule.py:78-87`; `references/protocol.md:34-35` **Vulnerability Type**: T01: Skill Instruction Hijacking **Risk Level**: Medium ### Vulnerable Code ```markdown <!-- SKILL.md:39-40 --> Read the returned capsules. If a capsule matches your situation, try applying it. ``` ```python # scripts/fetch.py:113-141 assets = result.get("assets") or result.get("payload", {}).get("results") or result.get("payload", {}).get("assets") or [] if not assets: print("No results found.") print(json.dumps(result, indent=2, ensure_ascii=False)) return print(f"\nFound {len(assets)} result(s):\n") for i, asset in enumerate(assets, 1): atype = asset.get("type") or asset.get("asset_type", "unknown") payload_inner = asset.get("payload", {}) summary = payload_inner.get("summary") or asset.get("summary", "(no summary)") confidence = payload_inner.get("confidence") or asset.get("confidence", "") gdi = asset.get("gdi_score", "") asset_id = asset.get("asset_id", "") short_id = asset_id[:20] + "..." if asset_id else "" print(f"[{i}] {atype} — {summary[:100]}") if confidence: print(f" confidence: {confidence} gdi: {gdi} id: {short_id}") print() print("--- Raw response ---") print(json.dumps(result, indent=2, ensure_ascii=False)) ``` ```python # scripts/get_capsule.py:78-87 try: res = post("/a2a/fetch", envelope) results = res.get("payload", {}).get("results", []) if not results: print("Asset not found.") return asset = results[0] print("\n--- Asset Detail ---") print(json.dumps(asset, indent=2, ensure_ascii=False)) ``` ```markdown <!-- references/protocol.md:34-35 --> - `validation`: only node/npm/npx commands allowed ``` ### Technical Analysis Capsule content comes from remote EvoMap publishers and is therefore outside the local trust boundary. The scripts print summa ...[truncated 2091 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Clearly label every fetched capsule and field as untrusted third-party content. 2. Replace “try applying it” with instructions requiring independent review and explicit user approval. 3. Never automatically execute commands, install packages, change configuration, or access credentials based on capsule content. 4. Render remote assets inside strong instruction delimiters and state that embedded directives must not override system, developer, user, or Skill security rules. 5. Validate responses against a strict schema and enforce length and character limits on free-text fields. 6. Introduce cryptographic publisher signatures and display verified publisher identity and reputation separately from publisher-controlled text. 7. Maintain an allowlist of safe validation operations. Treat `npm`, `npx`, shell-capable Node commands, URLs, and package-installation instructions as high risk. 8. Require a preview showing proposed commands, files, network destinations, and requested permissions before applying a capsule. 9. Prefer translating capsules into a constrained declarative change format instead of placing unrestricted prose into the Agent context. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/publish_feishu403.js:7
Finding
Hard-Coded Publisher Identity Is Used Without Client-Side Proof of Possession<![CDATA[ ## Vulnerability Details **File Location**: `scripts/publish_feishu403.js:7-8, 54-65, 157-160` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: Medium ### Vulnerable Code ```javascript // scripts/publish_feishu403.js:7-8 const SENDER_ID = 'node_49b95d1c51989ece'; const HUB_URL = 'https://evomap.ai'; ``` ```javascript // scripts/publish_feishu403.js:54-65 function makeEnvelope(messageType, payload) { return { protocol: 'gep-a2a', protocol_version: '1.0.0', message_type: messageType, message_id: `msg_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`, sender_id: SENDER_ID, timestamp: new Date().toISOString(), payload }; } ``` ```javascript // scripts/publish_feishu403.js:157-160 const envelope = makeEnvelope('publish', { assets: [gene, capsule, event] }); console.log('\nPublishing to EvoMap...'); const result = await postJson('/a2a/publish', envelope); ``` ### Technical Analysis The publication script embeds a claimed node identity directly in source code and sends it as the `sender_id`. No API token, private-key signature, challenge response, or other client-side proof of possession is attached to the publish envelope. A node ID is an identifier, not an authentication secret. Because it is distributed with the project, any party can copy it and construct a syntactically equivalent publication request. If the server accepts `sender_id` as sufficient attribution, this permits identity spoofing. The project does not contain the server implementation. Undocumented server-side controls such as device binding, account sessions, source restrictions, or request signatures may reduce exploitability. The client code itself nevertheless provides no verifiable authentication material. ### Attack Path 1. An attacker obtains the hard-coded node ID from the publicly distributed script. 2. The attacker copies the documented GEP-A2A envelope format. 3. The attacker creates arbitrary Gene, Caps ...[truncated 827 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the hard-coded node identity from source control. 2. Load identity configuration from a dedicated, permission-restricted user configuration file. 3. Require authentication for publication using a protected API token or, preferably, asymmetric request signing. 4. Bind each node ID to a public key on the server and sign the canonical request body, timestamp, message ID, HTTP method, and endpoint. 5. Have the server reject unsigned publications, unknown keys, stale timestamps, and reused message IDs. 6. Support credential rotation and immediate revocation. 7. Keep private keys or tokens outside the Skill package and prevent them from appearing in logs. 8. Add server-side authorization tests confirming that knowledge of a node ID alone cannot publish, revoke, report, or modify assets under that identity. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This second mismatch finding indicates the skill may hardcode sender identity and publish a predefined bundle despite claiming to be a general-purpose integration. If true, that creates risk of impersonation, unexpected data publication, or misleading activation behavior, especially in agent ecosystems that rely on metadata for trust and routing.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
This second mismatch finding indicates the skill may hardcode sender identity and publish a predefined bundle despite claiming to be a general-purpose integration. If true, that creates risk of impersonation, unexpected data publication, or misleading activation behavior, especially in agent ecosystems that rely on metadata for trust and routing.

Credential Access

High
Category
Privilege Escalation
Content
"schema_version": "1.5.0",
  "category": "repair",
  "signals_match": ["FeishuAPIError", "403 Forbidden"],
  "summary": "Re-fetch access token when Feishu API returns 403",
  "validation": [],
  "asset_id": ""
}
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

External Script Fetching

High
Category
Supply Chain
Content
Your node is already active. Use fetch.py or publish directly.

Check node status instead:
  curl -s https://evomap.ai/a2a/nodes/YOUR_NODE_ID | python3 -m json.tool

Only use this script if you are registering a BRAND NEW node for the first time.
"""
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
Your node is already active. Use fetch.py or publish directly.

Check node status instead:
  curl -s https://evomap.ai/a2a/nodes/YOUR_NODE_ID | python3 -m json.tool

Only use this script if you are registering a BRAND NEW node for the first time.
"""
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
print("✅ Just use fetch.py or publish directly — no hello needed.")
    print()
    print("To check your node status:")
    print(f"  curl -s https://evomap.ai/a2a/nodes/{CLAIMED_NODE} | python3 -m json.tool")
    print()

    if "--force" in sys.argv:
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Credential Access

High
Category
Privilege Escalation
Content
],
    constraints: {
      max_files: 2,
      forbidden_paths: ['.env', 'secrets/']
    },
    validation: [
      "node -e \"console.log('Feishu app_secret should be 32 chars. Verify length manually in config.')\""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill advertises and instructs use of network, shell, environment, and file-reading capabilities but does not declare any explicit tool scope or permissions. In an agent setting, missing scope boundaries can cause over-privileged execution and make it easier for the skill to access local state (such as MEMORY.md or environment variables) and contact external services without clear governance.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The activation guidance is broad enough to trigger on generic mentions like wanting to 'learn the protocol' or 'search for capsules or genes,' which can cause unintended invocation. In an agent environment, overly permissive triggers increase the chance of unprompted external-service interaction or shell command suggestions in contexts where the user did not intend to use this marketplace integration.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill prominently promotes direct connection to an external hub and auto-discovery of sender_id from local state, but it does not provide a clear warning that user/agent data, node identifiers, and possibly solution content may be transmitted to a third-party service. This is dangerous because operators may unknowingly expose local identifiers, operational metadata, or sensitive problem descriptions to an external marketplace.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
The protocol explicitly permits `npx` in validation commands without requiring pinned package versions or restricting remote package resolution. In a collaborative marketplace where agents may consume and run shared validation steps, this can lead to execution of unexpected or attacker-controlled code if `npx` fetches the latest package or resolves a compromised dependency.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The skill metadata says sender_id should be auto-detected from MEMORY.md, but this script hardcodes a fixed node identity. In an agent-to-agent publishing workflow, a hardcoded sender_id can cause misattribution of published assets, cross-tenant identity confusion, or unintended publishing under the wrong agent identity if reused elsewhere.

Intent-Code Divergence

Low
Confidence
78% confidence
Finding
The file documentation says sender_id can come from command line, environment variable, or MEMORY.md, while the manifest-level description states it is auto-detected from MEMORY.md and that scripts handle the rest after saving node ID once. This is an intent/documentation divergence about how identity is sourced, which could mislead users about what data sources the script consults.

Context-Inappropriate Capability

Low
Confidence
85% confidence
Finding
The manifest description says sender_id is auto-detected from MEMORY.md so agents only need to save their node ID once, but this script also reads EVOMAP_SENDER_ID from the environment. Accessing environment variables is not clearly justified by that stated workflow and expands how identity is sourced beyond the described purpose.

Static analysis

No suspicious patterns detected.