Back to skill

Security audit

Openclaw Pii Anonymizer

Security checks for vulnerabilities and agentic risk

Overview

This PII anonymizer is not clearly malicious, but it can send sensitive text to a configurable HTTP model endpoint and may return only partially scrubbed data as if it were anonymized.

Use this only for development or tightly controlled manual workflows. Keep OLLAMA_URL pinned to a trusted local Ollama instance, do not rely on the deprecated v1 script, and manually review output before sending it to any external API or using it with regulated or customer PII.

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

T09 · Insecure Skill Coding Practices

Error
Location
privacy-anonymize-v2.sh:59
Finding

Configurable Ollama Endpoint Can Receive Sensitive User Data

Content
View full analysis
/dev/null 2>&1; then # Ollama unavailable, return regex result echo "$output" exit 0 fi llm_result=$(curl -s --max-time 20 --fail "$OLLAMA_URL/v1/chat/completions" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"$MODEL\", \"messages\": [ {\"role\": \"system\", \"content\": \"You are a PII redaction tool. Replace person names with [NAME]. Keep already anonymized tokens like [SSN], [EMAIL], [PHONE], [WALLET], [IP], [PATH]. Output ONLY the redacted text with NO explanations.\"}, {\"role\": \"user\", \"content\": \"$(echo "$output" | sed 's/"/\\"/g' | tr '\n' ' ')\"} ], \"stream\": false, \"options\": {\"temperature\": 0.0} }") || { ``` From `privacy-anonymize.sh`: ```bash OLLAMA_URL="${OLLAMA_URL:-http://localhost:11434}" MODEL="${MODEL:-phi3:mini}" ``` ```bash if ! curl -s --max-time 10 --fail "$OLLAMA_URL/v1/models" >/dev/null 2>&1; then echo "Error: Ollama unavailable at $OLLAMA_URL" >&2 exit 1 fi ``` ```bash response=$(curl -s --max-time 30 --fail "$OLLAMA_URL/v1/chat/completions" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"$MODEL\", \"messages\": [ {\"role\": \"system\", \"content\": \"Strict anonymize ONLY. Replace PII with [PERSON]/[EMAIL]/[PATH]/[IP]/[PHONE]/[SSN]/[URL]/[ORG]. Output RAW cleaned text ONLY. No explanations/sentences/additions/changes. Example: 'Seth at /home' → '[PERSON] at [PATH]'.\"}, {\"role\": \"user\", \"content\": \"$input\"} ], \"stream\": false, \"options\": {\"temperature\": 0.1} }") || { ``` ### Technical Analysis Both scri ...[truncated 1826 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
privacy-anonymize.sh:17
Finding

Unescaped Input Permits JSON Request Injection in the Deprecated Anonymizer

Content
View full analysis
&2 exit 1 } echo "$response" | jq -r '.choices[0].message.content // empty' | tr -d '\n\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' || { echo "Error: jq parse failed" >&2 exit 1 } } ``` ### Technical Analysis The script interpolates `input` and `MODEL` directly into a manually constructed JSON document. It performs no JSON encoding before inserting these values. A quotation mark, backslash, or control character can terminate or alter the intended JSON string. A crafted value can append properties or message objects if the receiving service accepts the resulting document. Less sophisticated input can make the JSON invalid and deny anonymization. This is JSON-data injection rather than shell-command injection: shell metacharacters inside the expanded variable are not reparsed as shell syntax. The relevant security consequence is manipulation of the API request and model conversation structure. ### Attack Path 1. An attacker supplies text containing a JSON string terminator and attacker-selected JSON fields. 2. The script inserts that text directly after `"content": "`. 3. The submitted value clos ...[truncated 990 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
privacy-anonymize-v2.sh:64
Finding

Incomplete JSON Escaping Permits Request Manipulation in Version 2

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
privacy-anonymize-v2.sh:45
Finding

Anonymization Failures Return Partially Redacted Data as Successful Output

Content
View full analysis
/dev/null 2>&1; then # Ollama unavailable, return regex result echo "$output" exit 0 fi llm_result=$(curl -s --max-time 20 --fail "$OLLAMA_URL/v1/chat/completions" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"$MODEL\", \"messages\": [ {\"role\": \"system\", \"content\": \"You are a PII redaction tool. Replace person names with [NAME]. Keep already anonymized tokens like [SSN], [EMAIL], [PHONE], [WALLET], [IP], [PATH]. Output ONLY the redacted text with NO explanations.\"}, {\"role\": \"user\", \"content\": \"$(echo "$output" | sed 's/"/\\"/g' | tr '\n' ' ')\"} ], \"stream\": false, \"options\": {\"temperature\": 0.0} }") || { # LLM failed, return regex result echo "$output" exit 0 } final=$(echo "$llm_result" | jq -r '.choices[0].message.content // empty' | tr -d '\n\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') if [ -n "$final" ] && [ "$final" != "null" ]; then echo "$final" else echo "$output" fi ``` ### Technical Analysis The script treats its LLM layer as optional and returns the regex-only result when: - Input is shorter than 15 characters. - The word-pair heu ...[truncated 2066 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (13)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The README states that automatic hook interception and auto-anonymization do not work, yet the skill is presented as a privacy pipeline for external AI processing. This creates a serious risk that operators will assume inbound messages are being scrubbed automatically when they are not, leading to direct leakage of raw PII to downstream systems.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This is a serious trust-boundary mismatch for a privacy skill: the documentation claims local regex-plus-LLM scrubbing before external AI use, but the analyzed behavior indicates raw user input is sent directly to a model endpoint and key protections are either missing or different from what is claimed. For a PII anonymizer, inaccurate claims about what data is scrubbed, what model is used, and where raw input is transmitted can cause users to expose sensitive information under false assumptions of protection.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README explicitly demonstrates piping only 'anonymized' text to an external API without warning that the anonymization may miss some PII, especially since the document itself admits regex gaps and incomplete automatic interception. Users may reasonably infer that the pipeline fully protects sensitive data, causing residual personal data to be transmitted to third parties.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises shell-based installation and execution steps but does not declare any explicit tool scope such as permissions or allowed-tools. That weakens containment and review because operators cannot easily tell what command execution capability the skill expects, increasing the chance of overbroad execution in environments that rely on manifest-declared boundaries.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The usage example normalizes forwarding processed data to an external API without clearly warning users that their content still leaves the local system after anonymization. In the context of a privacy tool, that omission is risky because users may overestimate the protection level and send regulated or highly sensitive content off-system without informed consent or policy review.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The code performs external transmission via curl to a configurable endpoint and then sends the redaction candidate text for model processing. In a privacy-focused skill, this context makes the behavior more dangerous because the transmitted data may still contain the exact PII the tool is supposed to protect, especially names and contextual identifiers the regex pass misses.

Content

Scanner excerpt · privacy-anonymize-v2.sh (reported line 56)May include surrounding context.

sh
fi

# Step 3: LLM pass for names and contextual PII
if ! curl -s --max-time 5 --fail "$OLLAMA_URL/v1/models" >/dev/null 2>&1; then
  # Ollama unavailable, return regex result
  echo "$output"
  exit 0

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script sends partially processed user text to an HTTP-served LLM endpoint for additional redaction. Because regex redaction is incomplete by design and the LLM step is specifically intended to catch remaining names/contextual PII, sensitive data may still be transmitted off-process or off-host if OLLAMA_URL is changed from the localhost default, undermining the privacy guarantee of a scrubber.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script transmits user content to a local HTTP LLM service without any runtime disclosure, warning, or opt-in despite being presented as a privacy anonymizer. Users may reasonably expect all processing to remain local and safe, but the endpoint is configurable and uses cleartext HTTP, creating a meaningful confidentiality risk for sensitive input.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill claims a privacy-preserving hybrid scrubber, but the implementation sends raw user input directly to an LLM without any deterministic pre-redaction stage. In a PII-anonymization context, this mismatch is dangerous because the very data that should be protected is exposed to another service first, and LLM-only anonymization is not reliable enough to guarantee complete redaction.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The script makes network requests to a configurable endpoint via OLLAMA_URL, and the same variable is later used to send user content for anonymization. Although the default is localhost, the endpoint is not constrained, so an attacker or misconfiguration could redirect sensitive input to a remote host, increasing exfiltration risk in a privacy-focused skill.

Content

Scanner excerpt · privacy-anonymize.sh (reported line 12)May include surrounding context.

sh
exit 1
fi

if ! curl -s --max-time 10 --fail "$OLLAMA_URL/v1/models" >/dev/null 2>&1; then
  echo "Error: Ollama unavailable at $OLLAMA_URL" >&2
  exit 1
fi

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script transmits the supplied text to an HTTP API endpoint for processing, but provides no disclosure or consent mechanism despite being a PII anonymizer. Because users may reasonably expect local sanitization before any transfer, this can cause direct privacy violations and accidental disclosure of regulated or highly sensitive data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The inline documentation states 'Skip LLM if message is very short,' which refers to the original message. The implementation actually checks the length of the regex-processed output, so a longer input heavily reduced by replacements may skip the LLM while a short original input above 15 characters will not.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The inline file documentation identifies the script as using Ollama phi3:mini, while the skill description says the privacy pipeline uses Qwen2.5 as its LLM component. This is an active documentation-versus-stated-intent inconsistency about the core model used for anonymization.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.