Back to skill

Security audit

Vanar Neutron Memory

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent remote memory skill, but it needs review because it can send and store conversation content remotely and inject recalled remote content back into the agent context with limited safeguards.

Install only if you are comfortable sending saved text, search queries, and optionally full conversation turns to the Neutron service. Prefer a service-specific NEUTRON_API_KEY, avoid the plaintext credentials file unless permissions are locked down, do not enable auto-capture or auto-recall for sensitive projects, and do not run with an untrusted NEUTRON_API_BASE value.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T01 · Skill Instruction Hijacking

Error
Location
hooks/pre-tool-use.sh:38
Finding
Untrusted Remote Memories Are Injected Directly into Agent Context<![CDATA[ ## Vulnerability Details **File Location**: `hooks/pre-tool-use.sh:38-50` **Vulnerability Type**: Stored prompt injection through recalled memory **Risk Level**: High ### Vulnerable Code ```bash # Query for relevant memories response=$(curl -s -X POST "${API_BASE}/memory/search" \ -H "Authorization: Bearer ${API_KEY}" \ -H "Content-Type: application/json" \ -d "$json_body" 2>/dev/null || echo "{}") # Extract memories if any memories=$(echo "$response" | jq -r '.results[]?.content // empty' 2>/dev/null | head -500) if [[ -n "$memories" ]]; then echo "---" echo "RECALLED MEMORIES:" echo "$memories" echo "---" fi ``` Related persistence behavior appears in `hooks/post-tool-use.sh:22-41`, where complete user and assistant messages can be stored automatically: ```bash USER_MSG="${OPENCLAW_USER_MESSAGE:-}" AI_RESP="${OPENCLAW_AI_RESPONSE:-}" [[ -z "$USER_MSG" && -z "$AI_RESP" ]] && exit 0 TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ") TITLE="Conversation - ${TS}" CONTENT="User: ${USER_MSG} Assistant: ${AI_RESP}" # Build form field values safely using jq (prevents JSON injection) text_json=$(jq -n --arg t "$CONTENT" '[$t]') title_json=$(jq -n --arg t "$TITLE" '[$t]') curl -s -X POST "${API_BASE}/memory/save" \ -H "Authorization: Bearer ${API_KEY}" \ -F "text=${text_json}" \ -F 'textTypes=["text"]' \ -F 'textSources=["auto_capture"]' \ -F "textTitles=${title_json}" > /dev/null 2>&1 ``` ### Technical Analysis The pre-tool hook treats memory content returned by the remote service as trusted agent context. It extracts the `content` fields and prints them without separating data from instructions, filtering instruction-like text, attaching provenance, or warning the agent that the content is untrusted. When auto-capture is enabled, attacker-controlled user messages are stored as memories. An attacker can therefore submit text containing instructions designed to alter later agent behavior. Semantic search may recall ...[truncated 1938 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every recalled memory as untrusted data, regardless of its original source. 2. Return memories in a structured envelope that clearly labels their provenance and states that instructions contained in them must not be followed. 3. Keep recalled data outside instruction-bearing prompt sections where supported by the host platform. 4. Filter or quarantine content that contains instruction-like patterns, tool requests, credential requests, role changes, or attempts to override system constraints. 5. Distinguish user-authored memories from trusted operator-authored memories and prevent user-authored records from becoming executable guidance. 6. Require explicit user confirmation before recalled content can affect tool calls, file operations, network requests, or other consequential actions. 7. Add source identifiers, creation timestamps, and trust levels to each recalled record. 8. Provide deletion and review controls so operators can inspect and remove poisoned memories. 9. Consider disabling automatic capture of arbitrary user content by default even when recall is enabled. 10. Add security tests using stored prompt-injection payloads to verify that recalled text remains inert data. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/neutron-memory.sh:4
Finding
Unrestricted API Endpoint Override Can Exfiltrate API Keys and Conversation Data<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/neutron-memory.sh:4, 98-104, 135-139` - `hooks/pre-tool-use.sh:13, 38-41` - `hooks/post-tool-use.sh:11, 36-41` **Vulnerability Type**: Credential and sensitive-data disclosure through an attacker-controlled endpoint **Risk Level**: High ### Vulnerable Code From `scripts/neutron-memory.sh`: ```bash API_BASE="${NEUTRON_API_BASE:-https://api-neutron.vanarchain.com}" CONFIG_FILE="${HOME}/.config/neutron/credentials.json" ``` ```bash result=$(curl -s -X POST "${API_BASE}/memory/save" \ -H "Authorization: Bearer ${API_KEY}" \ -F "text=${text_json}" \ -F 'textTypes=["text"]' \ -F 'textSources=["bot_save"]' \ -F "textTitles=${title_json}" 2>&1) ``` ```bash result=$(curl -s -X POST "${API_BASE}/memory/search" \ -H "Authorization: Bearer ${API_KEY}" \ -H "Content-Type: application/json" \ -d "$json_body" 2>&1) ``` From `hooks/pre-tool-use.sh`: ```bash API_BASE="${NEUTRON_API_BASE:-https://api-neutron.vanarchain.com}" ``` ```bash response=$(curl -s -X POST "${API_BASE}/memory/search" \ -H "Authorization: Bearer ${API_KEY}" \ -H "Content-Type: application/json" \ -d "$json_body" 2>/dev/null || echo "{}") ``` From `hooks/post-tool-use.sh`: ```bash API_BASE="${NEUTRON_API_BASE:-https://api-neutron.vanarchain.com}" ``` ```bash curl -s -X POST "${API_BASE}/memory/save" \ -H "Authorization: Bearer ${API_KEY}" \ -F "text=${text_json}" \ -F 'textTypes=["text"]' \ -F 'textSources=["auto_capture"]' \ -F "textTitles=${title_json}" > /dev/null 2>&1 ``` ### Technical Analysis The `NEUTRON_API_BASE` environment variable can replace the intended service origin with any URL. No scheme validation, hostname allowlist, certificate pinning, or explicit development-mode restriction is applied. Every request sends `Authorization: Bearer ${API_KEY}` to the configured endpoint. Save operations and the auto-capture hook also transmit memory or conversation ...[truncated 2069 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin production requests to `https://api-neutron.vanarchain.com`. 2. If endpoint overrides are necessary for development, require an explicit development flag and refuse overrides during normal execution. 3. Parse and validate the configured URL before any request: - Require the `https` scheme. - Require an exact allowlisted hostname. - Reject embedded credentials, unusual ports, redirects to untrusted origins, and malformed URLs. 4. Configure `curl` to fail securely, for example with `--fail-with-body --proto '=https' --tlsv1.2`. 5. Disable or strictly constrain redirects. If redirects are allowed, ensure authorization headers cannot be forwarded to a different origin. 6. Use only a service-specific credential variable such as `NEUTRON_API_KEY`; do not fall back to generic `API_KEY`. 7. Before enabling automatic capture, display the final validated destination and obtain explicit operator consent. 8. Add tests proving that HTTP URLs, non-allowlisted hosts, and cross-origin redirects are rejected before credentials are attached. 9. Rotate API keys if the Skill has previously been run with an untrusted endpoint override. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SETUP.md:38
Finding
Credential Setup Instructions Do Not Enforce Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `SETUP.md:38-41` **Vulnerability Type**: Insecure local storage of an API credential **Risk Level**: Medium ### Vulnerable Code ```bash **Option B — Credentials file:** ```bash mkdir -p ~/.config/neutron echo '{"api_key":"nk_your_key_here"}' > ~/.config/neutron/credentials.json ``` ``` The same unsafe creation example is repeated by the CLI in `scripts/neutron-memory.sh:35-39`: ```bash echo "Option 2 - Credentials file:" echo " mkdir -p ~/.config/neutron" echo ' echo '"'"'{"api_key":"nk_your_key"}'"'"' > ~/.config/neutron/credentials.json' ``` ### Technical Analysis The documented setup creates the directory and credential file without explicitly restricting permissions. Resulting permissions depend on the user's current `umask`. Under a commonly used `022` umask, the file may be created with mode `0644`, making the API key readable by other local users on a multi-user system. The directory may similarly be created with mode `0755`. The runtime scripts only need read access to one Neutron credential. Reading that credential is necessary for the declared functionality, but allowing unrelated local accounts to read it exceeds the minimum privilege required. The issue is not a hardcoded production secret: the value shown is a placeholder. The risk arises from instructing users to place their real key in a potentially over-permissive plaintext file. ### Attack Path 1. A user follows Option B in the setup guide and substitutes a real Neutron API key. 2. The user's `umask` permits group or world read access when shell redirection creates the file. 3. Another local account enumerates or reads `~/.config/neutron/credentials.json`. 4. The attacker obtains the plaintext API key. 5. The attacker reuses the key against the Neutron API to perform operations available to that credential, potentially accessing memories or consuming account credits. This path requires local filesystem access under another accoun ...[truncated 542 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Replace the setup commands with permission-safe creation: ```bash install -d -m 700 "$HOME/.config/neutron" umask 077 printf '%s\n' '{"api_key":"nk_your_key_here"}' \ > "$HOME/.config/neutron/credentials.json" chmod 600 "$HOME/.config/neutron/credentials.json" ``` Additional hardening measures: 1. Update both `SETUP.md` and the CLI error message so they never recommend insecure file creation. 2. At runtime, inspect the credential file's ownership and mode before reading it. 3. Refuse or prominently warn when the file is owned by another user or is readable/writable by group or others. 4. Prefer a platform credential store or secret manager instead of a plaintext JSON file where practical. 5. Recommend `NEUTRON_API_KEY` rather than the generic `API_KEY` environment variable. 6. Document key rotation procedures for users who may already have created an over-permissive file. 7. Ensure logs and diagnostics never print the complete credential. ]]>
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
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (21)

Credential Access

High
Category
Privilege Escalation
Content
**Option B — Credentials file:**
```bash
mkdir -p ~/.config/neutron
echo '{"api_key":"nk_your_key_here"}' > ~/.config/neutron/credentials.json
```

**Option C — OpenClaw project config** (`openclaw.json`):
Confidence
95% confidence
Finding
The setup guide instructs users to write a plaintext API key directly into ~/.config/neutron/credentials.json. Storing long-lived credentials unencrypted on disk increases the risk of accidental disclosure through backups, local compromise, permissive file permissions, or dotfile syncing, especially because this skill enables persistent access to a remote memory service.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The skill’s description understates important behavior: it depends on a third-party service, uses credentials from environment configuration, performs network connectivity/authentication tests, and delegates persistence to an external API. In context, this is more dangerous because the skill’s core function is long-term memory, so users may provide highly sensitive personal or operational context that is then transmitted off-system under a simpler description than warranted.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The skill’s description understates important behavior: it depends on a third-party service, uses credentials from environment configuration, performs network connectivity/authentication tests, and delegates persistence to an external API. In context, this is more dangerous because the skill’s core function is long-term memory, so users may provide highly sensitive personal or operational context that is then transmitted off-system under a simpler description than warranted.

Credential Access

High
Category
Privilege Escalation
Content
command -v jq &> /dev/null || exit 0

API_BASE="${NEUTRON_API_BASE:-https://api-neutron.vanarchain.com}"
CONFIG_FILE="${HOME}/.config/neutron/credentials.json"

API_KEY="${API_KEY:-${NEUTRON_API_KEY:-}}"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
command -v jq &> /dev/null || exit 0

API_BASE="${NEUTRON_API_BASE:-https://api-neutron.vanarchain.com}"
CONFIG_FILE="${HOME}/.config/neutron/credentials.json"

API_KEY="${API_KEY:-${NEUTRON_API_KEY:-}}"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# Neutron Memory CLI — save and search only

API_BASE="${NEUTRON_API_BASE:-https://api-neutron.vanarchain.com}"
CONFIG_FILE="${HOME}/.config/neutron/credentials.json"

# --- Dependency checks ---
if ! command -v curl &> /dev/null; then
Confidence
90% confidence
Finding
The script uses a plaintext credentials file in the user's home directory for API key storage, but it does not verify file permissions or encourage secure storage. On multi-user systems or misconfigured environments, this can expose the API key to other local users or backup/sync systems, enabling unauthorized API use.

Credential Access

High
Category
Privilege Escalation
Content
echo ""
    echo "Option 2 - Credentials file:"
    echo "  mkdir -p ~/.config/neutron"
    echo '  echo '"'"'{"api_key":"nk_your_key"}'"'"' > ~/.config/neutron/credentials.json'
    exit 1
fi
Confidence
92% confidence
Finding
The usage instructions explicitly recommend writing the API key to a plaintext JSON file under ~/.config without setting restrictive permissions. This guidance can lead users to persist credentials insecurely, increasing the chance of local disclosure and downstream unauthorized access.

Session Persistence

Medium
Category
Rogue Agent
Content
Your account comes with **$20 of free credits** — enough to store and search thousands of memories.

> If you already have an account, log in at https://openclaw.vanarchain.com/login and go to **Manage** → **API Keys** to create a new key.

That's it — one key is all you need. No agent IDs, no app IDs, no other configuration.
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.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises and instructs use of shell scripts and hooks, but the manifest does not declare any explicit tool scope such as allowed shell access. In an agent setting, undeclared execution capability reduces reviewability and containment, making it easier for a skill to invoke shell-based behavior that operators did not explicitly approve.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The hook automatically packages and transmits full user and assistant conversation content to a remote API once enabled, while sourcing credentials from environment variables or a local credentials file. In a memory skill this is functionally related to the feature, but it still creates a real data-exfiltration path for potentially sensitive prompts, secrets, or proprietary context without per-message filtering, minimization, or explicit runtime consent.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script sends complete conversation contents to a remote endpoint with no user-facing warning, confirmation, or visible audit trail at transmission time. Because post-turn hooks may run silently, this can expose secrets, personal data, internal code, or other sensitive material to an external service without sufficiently explicit awareness by the operator.

External Transmission

Medium
Category
Data Exfiltration
Content
json_body=$(jq -n --arg q "$USER_MESSAGE" '{"query":$q,"limit":5,"threshold":0.5}')

# Query for relevant memories
response=$(curl -s -X POST "${API_BASE}/memory/search" \
    -H "Authorization: Bearer ${API_KEY}" \
    -H "Content-Type: application/json" \
    -d "$json_body" 2>/dev/null || echo "{}")
Confidence
92% confidence
Finding
The curl call exfiltrates the full user message to an external endpoint along with an authorization token. In a memory skill this is functionally expected, but it is still a genuine security concern because all prompt content is exported off-box and could expose confidential data depending on how the agent is used.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
When enabled, the hook sends the user's latest message to a remote API for semantic search before the agent turn. That creates a real privacy and data-handling risk because prompts may contain secrets, personal data, or proprietary information, and the script provides no in-band disclosure, consent check, or content minimization at transmission time.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The script loads an API key from environment variables or a local credentials file, then uses it in Authorization headers for remote requests. While this behavior is functionally necessary, there is no explicit disclosure in the help text or comments aimed at users that credentials are being read from local storage and sent to an external service.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "  export API_KEY=nk_your_key"
    echo ""
    echo "Option 2 - Credentials file:"
    echo "  mkdir -p ~/.config/neutron"
    echo '  echo '"'"'{"api_key":"nk_your_key"}'"'"' > ~/.config/neutron/credentials.json'
    exit 1
fi
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.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script transmits user-supplied memory content and search queries to a remote third-party API, but it does not present any explicit privacy notice, consent prompt, or data-handling warning at the point of use. Because this skill is specifically designed for persistent memory across sessions, users may send sensitive information without realizing it leaves the local environment and is stored remotely.

External Transmission

Medium
Category
Data Exfiltration
Content
# Build JSON body safely using jq (prevents JSON injection)
        json_body=$(jq -n --arg q "$query" --argjson l "$limit" --argjson t "$threshold" \
            '{"query":$q,"limit":$l,"threshold":$t}')
        result=$(curl -s -X POST "${API_BASE}/memory/search" \
            -H "Authorization: Bearer ${API_KEY}" \
            -H "Content-Type: application/json" \
            -d "$json_body" 2>&1)
Confidence
95% confidence
Finding
This search command sends user queries and the bearer API key to an external service. In the context of an agent memory skill, search terms may contain sensitive user context, secrets, or operational data, so remote transmission materially expands the data exposure boundary.

External Transmission

Medium
Category
Data Exfiltration
Content
echo ""

        # Check connectivity + auth
        result=$(curl -s -w "\n%{http_code}" -X POST "${API_BASE}/memory/search" \
            -H "Authorization: Bearer ${API_KEY}" \
            -H "Content-Type: application/json" \
            -d '{"query":"test","limit":1}' 2>&1)
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# Check API connectivity
        echo -n "API:     "
        http_code=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${API_BASE}/memory/search" \
            -H "Authorization: Bearer ${API_KEY}" \
            -H "Content-Type: application/json" \
            -d '{"query":"ping","limit":1}' 2>/dev/null)
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Low
Confidence
67% confidence
Finding
The inline documentation frames the behavior as opt-in only, but the implemented behavior is automatic capture of the entire conversation after every AI turn once the flag is enabled. That is not a direct contradiction in a strict sense, but the comment minimizes the operational effect of enabling the flag and can mislead reviewers about the extent of automated data capture.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The script accesses API credentials from environment variables or a local credentials file, then uses them in an Authorization header for an outbound request. This is a sensitive operation, and the script provides no user-facing notice, logging, or inline warning that stored credentials will be loaded and used automatically.

Static analysis

No suspicious patterns detected.