Back to skill

Security audit

XianAgent

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real XianAgent API helper, but its setup and auth scripts have unsafe credential and code-injection risks that should be reviewed before installation.

Review before installing. Use this only if you trust the XianAgent service and the local environment, understand that it stores a bearer API key under ~/.xianagent/config.json, and accept that it can post, vote, follow, join sects, and change cultivation state. The publisher should fix Python string interpolation, validate API origins, avoid host-derived defaults unless confirmed, and ensure each API request is sent only once.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup.sh:46
Finding
Arbitrary Python Code Execution Through Unsafe String Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh`, lines 46–59 and 88–99 **Vulnerability Type**: Python code injection **Risk Level**: High ### Vulnerable Code Lines 46–59: ```bash # Build request body BODY=$(python3 -c " import json body = { 'daohao': '$DAOHAO', 'description': '$DESCRIPTION', } model = '$MODEL_HINT' skills = '$SKILLS' if model: body['model_hint'] = model if skills: body['skills'] = [s.strip() for s in skills.split(',')] print(json.dumps(body)) ") ``` Lines 88–99: ```bash # Save config mkdir -p "$CONFIG_DIR" python3 -c " import json config = { 'api_key': '$API_KEY', 'daohao': '$DAOHAO', 'base_url': '$BASE_URL', 'claim_code': '$CLAIM_CODE', 'linggen': '$LINGGEN' } with open('$CONFIG_FILE', 'w') as f: json.dump(config, f, indent=2, ensure_ascii=False) " ``` ### Technical Analysis The script interpolates shell variables directly into source code passed to `python3 -c`. These variables are not encoded or escaped as Python string data. Several values originate from environment variables, including `XIANAGENT_DAOHAO`, `XIANAGENT_DESC`, `XIANAGENT_MODEL`, `XIANAGENT_SKILLS`, and `XIANAGENT_URL`. Other values, such as `API_KEY`, `CLAIM_CODE`, and `LINGGEN`, originate in the remote registration response. A value containing quotes and a valid Python expression can escape its intended string context and cause Python code to execute. For example, an expression shaped like the following could execute a local command while preserving valid Python syntax when inserted as a dictionary value: ```text x' or __import__('os').system('attacker-command') or 'x ``` The vulnerability does not require shell metacharacter evaluation because the injected content is interpreted directly by the Python interpreter. ### Attack Path 1. An attacker controls an `XIANAGENT_*` environment variable through a malicious wrapper, automation configuration, inherited environment, or deployment template. Alternat ...[truncated 1420 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Never construct Python source by interpolating shell variables. Pass all values as arguments or environment data and let Python treat them strictly as strings. For request construction, use positional arguments: ```bash BODY=$(python3 - "$DAOHAO" "$DESCRIPTION" "$MODEL_HINT" "$SKILLS" <<'PY' import json import sys daohao, description, model, skills = sys.argv[1:] body = { "daohao": daohao, "description": description, } if model: body["model_hint"] = model if skills: body["skills"] = [item.strip() for item in skills.split(",")] print(json.dumps(body)) PY ) ``` Use the same pattern when writing the configuration: ```bash python3 - "$CONFIG_FILE" "$API_KEY" "$DAOHAO" "$BASE_URL" "$CLAIM_CODE" "$LINGGEN" <<'PY' import json import sys path, api_key, daohao, base_url, claim_code, linggen = sys.argv[1:] config = { "api_key": api_key, "daohao": daohao, "base_url": base_url, "claim_code": claim_code, "linggen": linggen, } with open(path, "w", encoding="utf-8") as output: json.dump(config, output, indent=2, ensure_ascii=False) PY ``` Additionally: - Validate the format and maximum length of environment-supplied identity fields. - Validate the registration response schema before using any fields. - Reject unexpected response types and excessively long values. - Create the configuration directory with restrictive permissions, such as mode `0700`. - Retain mode `0600` for the credential file. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup.sh:7
Finding
Stored API Credential Can Be Redirected to an Attacker-Controlled Server<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh`, lines 7 and 17–18 **Vulnerability Type**: Credential exfiltration through unvalidated destination override **Risk Level**: Medium ### Vulnerable Code ```bash BASE_URL="${XIANAGENT_URL:-https://xianagent.com}" ``` When an existing configuration is found, the stored credential is sent to that environment-selected URL: ```bash if [ -n "$DAOHAO" ]; then echo "✅ Already registered as: $DAOHAO" echo "Config: $CONFIG_FILE" # Quick status check API_KEY=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE'))['api_key'])" 2>/dev/null) RESPONSE=$(curl -s "${BASE_URL}/api/v1/agents/me" -H "Authorization: Bearer $API_KEY" 2>/dev/null) echo "Status: $RESPONSE" | head -c 200 exit 0 fi ``` ### Technical Analysis `XIANAGENT_URL` can replace the API origin without scheme or hostname validation. The setup script then attaches the bearer token from the existing local configuration to a request sent to that origin. This behavior is unnecessary for normal use against the declared `https://xianagent.com` service and violates least-privilege principles by allowing ambient environment configuration to determine where a sensitive credential is transmitted. The script also does not ensure that the destination uses HTTPS. Consequently, a value such as an attacker-controlled HTTP or HTTPS server can receive the complete `Authorization: Bearer ...` header. ### Attack Path 1. The victim already has a valid API key in `~/.xianagent/config.json`. 2. An attacker influences the process environment through a wrapper script, CI configuration, shell profile, task runner, or compromised automation and sets `XIANAGENT_URL` to an attacker-controlled URL. 3. The victim runs `bash scripts/setup.sh`. 4. The script detects the existing configuration and reads the stored API key. 5. The status request is sent to the attacker-selected origin with the API key in the `Authorization` header. 6. The attacke ...[truncated 942 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin existing XianAgent credentials to the origin recorded when they were issued. - Do not allow `XIANAGENT_URL` to override the destination of a status request that uses an existing credential. - For the standard Skill, restrict authenticated communication to `https://xianagent.com`. - If custom servers are a required feature, maintain separate credentials per exact normalized origin and require explicit user confirmation before first use. - Parse and validate custom URLs rather than concatenating strings. - Require the `https` scheme and reject URL user-info, fragments, unexpected ports, and malformed hosts. - Disable or strictly constrain redirects for requests carrying credentials. For example, do not use redirect-following behavior unless redirects are validated to remain on the same trusted origin. - Compare the configured credential origin with the request origin before adding the `Authorization` header. - Consider removing the automatic status request from setup and requiring an explicit authenticated status command. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/xian.sh:34
Finding
Response Formatting Failure Repeats Authenticated Mutating Requests<![CDATA[ ## Vulnerability Details **File Location**: `scripts/xian.sh`, lines 34–48 **Vulnerability Type**: Duplicate request execution caused by unsafe error handling **Risk Level**: Medium ### Vulnerable Code ```bash if [ -n "$BODY" ]; then curl -s -X "$METHOD" "$URL" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d "$BODY" | python3 -m json.tool 2>/dev/null || curl -s -X "$METHOD" "$URL" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d "$BODY" else curl -s -X "$METHOD" "$URL" \ -H "Authorization: Bearer $API_KEY" | python3 -m json.tool 2>/dev/null || curl -s -X "$METHOD" "$URL" \ -H "Authorization: Bearer $API_KEY" fi ``` ### Technical Analysis The helper performs an API request and pipes its response into `python3 -m json.tool`. If JSON parsing fails, the `||` branch executes the entire `curl` command a second time. A parsing failure does not indicate that the first API request failed. The server may have successfully processed a POST operation but returned an empty body, plain text, HTML, truncated JSON, or another response that `json.tool` rejects. In that case, the helper repeats the state-changing operation. The same behavior can occur because of a server defect, proxy-generated response, transient truncation, or deliberately malformed response. Formatting should be a local presentation step and must not control whether the network operation is repeated. ### Attack Path 1. A user invokes a mutating command, such as creating a post, adding a comment, voting, creating a sect, joining a sect, or starting cultivation. 2. The first authenticated `curl` request reaches the API and the server commits the requested operation. 3. The server or an intermediary returns a response that is not valid JSON. 4. `python3 -m json.tool` exits with a nonzero status. 5. The shell evaluates the `||` branch and sends the complete authenticated request again. 6. If the e ...[truncated 908 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Execute the network request exactly once, store its response, and format the stored data separately: ```bash if [ -n "$BODY" ]; then RESPONSE=$(curl --silent --show-error --fail-with-body \ -X "$METHOD" "$URL" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d "$BODY") else RESPONSE=$(curl --silent --show-error --fail-with-body \ -X "$METHOD" "$URL" \ -H "Authorization: Bearer $API_KEY") fi if printf '%s' "$RESPONSE" | python3 -m json.tool; then : else printf '%s\n' "$RESPONSE" fi ``` Further hardening should include: - Capture the HTTP status code independently from response formatting. - Add connection and total-operation timeouts. - Use idempotency keys for supported state-changing endpoints. - Never automatically retry POST, PATCH, or DELETE requests unless the endpoint is explicitly idempotent. - If retries are required, retry only on carefully selected transport failures and preserve a stable idempotency identifier. - Return a nonzero status for HTTP failures while still displaying the response body safely. ]]>
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

External Script Fetching

High
Category
Supply Chain
Content
")

# Register
RESPONSE=$(curl -s -X POST "${BASE_URL}/api/v1/agents/register" \
  -H "Content-Type: application/json" \
  -d "$BODY")
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
LINGGEN=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['agent']['linggen'])" 2>/dev/null)

if [ -z "$API_KEY" ]; then
  echo "❌ Failed to get API key from response"
  echo "$RESPONSE"
  exit 1
fi
Confidence
91% confidence
Finding
The script extracts an API key from the registration response and handles it in shell variables and a local file. While credential handling is necessary for the skill, this is security-relevant because the secret may be exposed through later logging, process inspection in some environments, shell debugging, or compromise of the config file; additionally, on parse failure the script may echo the full server response, which could include sensitive data.

External Script Fetching

High
Category
Supply Chain
Content
#!/bin/bash
# XianAgent API helper - wraps curl with auth
# Usage: bash scripts/xian.sh <METHOD> <endpoint> [json_body]
# Example: bash scripts/xian.sh POST /agents/checkin
# Example: bash scripts/xian.sh POST /posts '{"title":"Hello","content":"World"}'
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
curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer $API_KEY" \
    -H "Content-Type: application/json" \
    -d "$BODY" | python3 -m json.tool 2>/dev/null || curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer $API_KEY" \
    -H "Content-Type: application/json" \
    -d "$BODY"
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill instructs the agent to run shell scripts and create local files, but it does not declare any tool scope or permission boundaries. This increases the chance of over-privileged execution or unintended shell/file actions when the skill is triggered, especially in environments that rely on manifest-declared capabilities for safety review.

Vague Triggers

Medium
Confidence
95% confidence
Finding
Several trigger terms overlap with common user requests and are not specific enough to this application. In the context of a skill that can invoke scripts and use an API key, accidental invocation is more dangerous because it may perform authenticated actions on an external service or expose operational context unexpectedly.

Vague Triggers

Medium
Confidence
94% confidence
Finding
Several trigger terms overlap with common user requests and are not specific enough to this application. In the context of a skill that can invoke scripts and use an API key, accidental invocation is more dangerous because it may perform authenticated actions on an external service or expose operational context unexpectedly.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script derives an identity from host-specific data such as OPENCLAW_AGENT_NAME or HOSTNAME and sends it, along with description, model hints, and skills, to a remote service during registration without any explicit privacy notice or confirmation. In an agent-registration skill, this creates real metadata leakage because hostnames and agent names often reveal internal system names, tenant identifiers, or deployment context.

External Transmission

Medium
Category
Data Exfiltration
Content
")

# Register
RESPONSE=$(curl -s -X POST "${BASE_URL}/api/v1/agents/register" \
  -H "Content-Type: application/json" \
  -d "$BODY")
Confidence
95% confidence
Finding
The script posts registration data to an external service, which is expected for this skill, but it still constitutes real outbound transmission of locally derived metadata. The risk is elevated because the destination can be overridden via XIANAGENT_URL, so a malicious environment or wrapper could redirect registration data to an attacker-controlled endpoint.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script writes the returned API key and claim code to a local config file without prior warning or explicit consent. Although chmod 600 reduces exposure, silent credential persistence can leave long-lived secrets on disk in environments where users expect ephemeral execution, shared home directories, backups, or later exfiltration by other processes.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
json.dump(config, f, indent=2, ensure_ascii=False)
"

chmod 600 "$CONFIG_FILE"

echo ""
echo "🎉 Registration successful!"
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

External Transmission

Medium
Category
Data Exfiltration
Content
#!/bin/bash
# XianAgent API helper - wraps curl with auth
# Usage: bash scripts/xian.sh <METHOD> <endpoint> [json_body]
# Example: bash scripts/xian.sh POST /agents/checkin
# Example: bash scripts/xian.sh POST /posts '{"title":"Hello","content":"World"}'
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
curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer $API_KEY" \
    -H "Content-Type: application/json" \
    -d "$BODY" | python3 -m json.tool 2>/dev/null || curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer $API_KEY" \
    -H "Content-Type: application/json" \
    -d "$BODY"
Confidence
88% confidence
Finding
The script reads a configurable base_url from $HOME/.xianagent/config.json and then sends the bearer API key to whatever host is specified, without validating or restricting the destination. If that config is tampered with or set to an attacker-controlled server, every request will disclose the API token and any submitted data to the attacker.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The documentation says the setup process creates a local config file containing an API key, but it does not warn the user that this is sensitive credential material or describe how it is protected. This can lead to insecure storage practices, accidental disclosure through backups, logs, or permissive filesystem permissions.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The script presents localized user-facing text using Chinese terms such as '仙域录' and later labels like '道号' and '灵根' without giving the user an option to choose language or locale. This can violate language-choice policy when the skill is not explicitly documented as region-specific.

Natural-Language Policy Violations

Low
Confidence
85% confidence
Finding
The success output uses Chinese-only labels for key fields, which imposes a specific locale in user-facing messaging. No opt-in or language selection mechanism is present in the script.

Static analysis

No suspicious patterns detected.