Back to skill

Security audit

Grago

Security checks for vulnerabilities and agentic risk

Overview

Grago is transparent about being a local research helper, but it gives an agent broad shell, file, network, and installer authority that needs careful review before use.

Install only on a dedicated, trusted single-user machine where you are comfortable letting the OpenClaw agent run shell commands with your user permissions. Do not use it on shared, public-facing, or sensitive systems. Review commands and sources.yaml files carefully, keep api_base pointed at localhost unless you intend to send data elsewhere, and prefer installing Ollama through a trusted package manager instead of running the bundled curl-to-shell installer path.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
grago.sh:101
Finding
Agent-Controlled Arbitrary Shell Command Execution<![CDATA[ ## Vulnerability Details **File Location**: `grago.sh:101`, `grago.sh:153`, `grago.sh:184`, and `grago.sh:187` **Vulnerability Type**: Command injection through unrestricted `eval` **Risk Level**: Critical ### Vulnerable Code ```bash if [[ -n "$transform" ]]; then data=$(echo "$data" | eval "$transform") || err "Transform failed: $transform" fi ``` ```bash if [[ -n "$transform" ]]; then data=$(echo "$data" | eval "$transform" 2>/dev/null) || data="[transform failed]" fi ``` ```bash local data data=$(eval "$fetch_cmd") || err "Fetch command failed" if [[ -n "$transform_cmd" ]]; then data=$(echo "$data" | eval "$transform_cmd") || err "Transform failed" fi ``` ### Technical Analysis The `fetch`, `research`, and `pipe` commands pass command-line arguments or YAML-derived transformation values directly to the shell through `eval`. No command allowlist, argument separation, metacharacter validation, sandbox, user confirmation, or privilege reduction is applied. Because `eval` reparses its argument as shell syntax, an attacker can use command substitution, redirection, pipelines, separators, or subshells to execute commands unrelated to data fetching. The AI-facing documentation explicitly encourages an OpenClaw agent to populate these parameters, meaning prompt injection affecting the agent can reach the execution sink. The security documentation acknowledges this behavior, but disclosure does not constrain or mitigate the execution capability. General-purpose shell access is substantially broader than the minimum privilege required to fetch URLs and perform fixed data transformations. ### Attack Path 1. An attacker places malicious instructions in content processed by the OpenClaw agent or otherwise influences a research request. 2. The compromised agent constructs a Grago invocation containing attacker-controlled shell syntax, for example in `--fetch` or `--transform`. 3. `cmd_pipe`, `cmd_fetch`, or `cmd_research` assigns that value to a ...[truncated 969 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove every use of `eval`. 2. Replace free-form commands with a strict operation schema, such as predefined `curl`, `jq`, `grep`, and `tail` actions with separately represented arguments. 3. Execute commands using Bash arrays rather than reconstructed command strings: ```bash command_args=(jq "$filter") printf '%s' "$data" | "${command_args[@]}" ``` 4. Allowlist supported executables and options, and reject shell metacharacters, redirections, command substitutions, and environment assignments. 5. Require explicit user approval before any operation that reads local files, writes files, or invokes external processes. 6. Run transformations in a sandbox or isolated container with a read-only filesystem, restricted network access, resource limits, and a dedicated unprivileged account. 7. Treat agent-generated command arguments as untrusted even in single-user environments, because external content can prompt-inject the agent. 8. Add tests demonstrating that payloads containing separators, substitutions, pipelines, and redirections cannot escape the intended operation. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
install.sh:29
Finding
Unverified Remote Installer Download and Execution<![CDATA[ ## Vulnerability Details **File Location**: `install.sh:29` **Vulnerability Type**: Mutable remote payload retrieval and immediate execution **Risk Level**: Critical ### Vulnerable Code ```bash curl -fsSL https://ollama.ai/install.sh | sh ``` ### Technical Analysis The installer retrieves the current contents of a remote URL and pipes them directly into `sh`. The payload is not pinned to a reviewed release and is not verified using a cryptographic signature or a hardcoded checksum. HTTPS protects the connection in transit but does not protect users from an upstream compromise, compromised hosting infrastructure, unauthorized changes to the installation endpoint, or unexpected future modifications. The code actually executed can therefore differ from the code reviewed during this audit. Piping directly to the shell also prevents the user from inspecting the exact payload before execution. Any privilege escalation, package installation, service creation, or filesystem modification performed by the remote script occurs outside the reviewed project code. ### Attack Path 1. The user runs the local `install.sh`. 2. Ollama is not found on the system, causing the Linux installation branch to execute. 3. The installer downloads the current payload from `https://ollama.ai/install.sh`. 4. The downloaded bytes are sent directly to `sh` without integrity or authenticity verification beyond TLS. 5. If the endpoint or its delivery chain is compromised, attacker-controlled commands execute immediately. 6. The payload receives the permissions of the installer process and may request or invoke additional elevated privileges. ### Impact Assessment A compromised remote installer can execute arbitrary commands with the installer user's privileges. Depending on how the upstream script operates and whether elevated privileges are granted, the possible scope includes: - Installation or replacement of system binaries. - Theft of local credentials and user data. - Mo ...[truncated 236 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin Ollama to a specific reviewed release rather than retrieving a mutable installation script. 2. Download the artifact to a temporary file without executing it immediately. 3. Verify a cryptographic signature from a trusted, pinned signing key or compare the artifact against a hardcoded checksum obtained through a separate trusted channel. 4. Abort installation if verification fails. 5. Display the source, version, checksum, and intended system changes before requesting confirmation. 6. Prefer an operating-system package manager with signed package metadata where available. 7. Avoid executing installation logic with administrative privileges unless a specific operation requires them. 8. Document the exact third-party version and update procedure so dependency changes receive a separate security review. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
grago.sh:137
Finding
Unrestricted Local File Read with Model Endpoint Disclosure<![CDATA[ ## Vulnerability Details **File Location**: `grago.sh:137-145` and `grago.sh:162` **Vulnerability Type**: Arbitrary file read and potential sensitive-data disclosure **Risk Level**: High ### Vulnerable Code ```bash case "$type" in web|api) data=$(curl -sL --max-time "$TIMEOUT" "$url" 2>/dev/null) || { log "WARN: Failed $name"; continue; } ;; file) local path path=$(yq -r ".sources[$i].path" "$sources_file") data=$(cat $path 2>/dev/null) || { log "WARN: Failed $name"; continue; } ;; esac ``` ```bash local result result=$(echo "$combined" | analyze "${prompt:-Analyze the following data sources and provide key insights.}") ``` The analysis function can use a configurable endpoint: ```bash local api_base api_base=$(get_config "api_base" "http://localhost:11434/v1") curl -s "${api_base}/chat/completions" \ -H "Content-Type: application/json" \ -d "$payload" | jq -r '.choices[0].message.content // "Error: no response"' ``` ### Technical Analysis A YAML sources file can specify `type: file` and select any path readable by the Grago process. There is no approved-directory policy, canonical-path validation, symlink restriction, sensitive-file denylist, or user confirmation. The path is also expanded without quotes in `cat $path`. This permits shell field splitting and pathname expansion, allowing one YAML value to match or reference multiple files. Although this line does not itself invoke `eval`, its expansion behavior broadens the set of files that can be read. The resulting content is appended to `combined` and automatically supplied to the analysis function. Ollama is attempted first, but if unavailable, the fallback sends the data to the configurable `api_base`. That setting is not restricted to loopback, so local file content can be disclosed to a remote model endpoint. ### Attack Path 1. An attacker supplies a malicious sources file or influences an agent to generate one. 2. The file contains a source with `typ ...[truncated 992 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable local file sources by default. 2. Require the user to configure explicit approved root directories. 3. Resolve each requested path to its canonical form and verify that it remains under an approved root. 4. Reject symlinks, device files, sockets, procfs/sysfs paths, credential directories, and other sensitive locations. 5. Quote the path as `cat -- "$path"` and disable unintended glob expansion. 6. Require interactive confirmation that displays the canonical file path before reading it. 7. Enforce a loopback-only model endpoint by default and reject non-loopback `api_base` values unless the user explicitly enables remote transmission. 8. Clearly warn users before local content is sent to any remote endpoint. 9. Apply per-source size limits and redact common secret formats before model submission. 10. Run the file-reading component under a dedicated account with access only to approved research data. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
grago.sh:98
Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `grago.sh:98` and `grago.sh:132` **Vulnerability Type**: Server-side request forgery through unvalidated URLs and redirects **Risk Level**: High ### Vulnerable Code ```bash local data data=$(curl -sL --max-time "$TIMEOUT" "$url") || err "Failed to fetch: $url" ``` ```bash case "$type" in web|api) data=$(curl -sL --max-time "$TIMEOUT" "$url" 2>/dev/null) || { log "WARN: Failed $name"; continue; } ;; ``` ### Technical Analysis The `fetch` and `research` paths accept arbitrary URLs and pass them to `curl` without validating the scheme, hostname, port, or resolved address. The `-L` option follows redirects, but redirect destinations are not revalidated. Consequently, an attacker who controls an agent request or YAML source can cause requests from the trusted Grago host to loopback services, private network systems, link-local addresses, or cloud metadata endpoints. The host may have access to services that are not reachable by the attacker directly. Responses are returned to the caller or supplied to the model for analysis, creating a channel through which internal response data may be exposed. ### Attack Path 1. An attacker influences a Grago fetch request or a `sources.yaml` URL. 2. The attacker supplies an internal destination directly or an external URL that redirects to one. 3. Grago invokes `curl -sL` from the trusted host. 4. `curl` connects to the internal or link-local target and follows redirects without destination restrictions. 5. The response is printed or included in model analysis. 6. The attacker uses the result to enumerate internal services, retrieve local API data, or access cloud instance metadata. ### Impact Assessment The vulnerability can provide network access from the Grago host to otherwise inaccessible resources. Depending on the deployment environment, the scope may include: - Loopback-only administration or model APIs. - Services on private corporate or home netw ...[truncated 340 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only required schemes, preferably `https`. 2. Resolve destination hostnames before connecting and reject loopback, link-local, private, multicast, unspecified, and reserved address ranges. 3. Re-resolve and revalidate every redirect destination, or disable redirects entirely. 4. Use an explicit domain allowlist for agent-accessible research sources. 5. Reject URLs containing embedded credentials or unsupported ports. 6. Protect against DNS rebinding by binding requests to the validated resolved address while preserving correct TLS hostname verification. 7. Block access to known cloud metadata destinations at both the application and host firewall layers. 8. Run fetches in a network sandbox with no access to loopback or private network ranges. 9. Limit response size, request duration, redirect count, and supported protocols. 10. Log denied destinations without logging embedded credentials or other sensitive URL components. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (22)

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The fetch command executes user-supplied shell via eval in --transform, enabling arbitrary command execution in the context of the user running the script. Because this capability is exposed as part of routine data processing, it can be abused for code execution, data theft, or destructive local actions if arguments or source definitions are untrusted.

External Script Fetching

High
Category
Supply Chain
Content
exit 1
    fi
  else
    curl -fsSL https://ollama.ai/install.sh | sh
  fi
  echo -e "${GREEN}✓ Ollama installed${NC}"
else
Confidence
99% confidence
Finding
`curl -fsSL https://ollama.ai/install.sh | sh` downloads executable code from an external source and runs it immediately. In installer context this is especially dangerous because users expect setup scripts to make privileged system changes, so a compromised upstream script can install malware, alter configuration, or exfiltrate secrets with little visibility.

Chaining Abuse

High
Category
Tool Misuse
Content
exit 1
    fi
  else
    curl -fsSL https://ollama.ai/install.sh | sh
  fi
  echo -e "${GREEN}✓ Ollama installed${NC}"
else
Confidence
99% confidence
Finding
The `| sh` construct is a classic unsafe chaining pattern because it turns network data directly into executed commands. It removes opportunities for validation, auditing, and user review, so any compromise of the fetched content immediately becomes code execution on the host.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
**Grago executes shell commands by design.** This is intentional and necessary — local LLMs can't use tools natively, so Grago bridges the gap by running commands on your behalf.

**Risk:** If your OpenClaw agent is compromised or prompt-injected, Grago can execute arbitrary commands on your machine.

**Safe for:**
- ✅ Personal Mac Mini / VPS running your own OpenClaw agent
Confidence
98% confidence
Finding
The skill explicitly grants an agent the ability to execute shell commands and acknowledges that a compromised or prompt-injected agent could run arbitrary commands on the host. In agentic systems, unrestricted shell access is highly dangerous because it can lead to code execution, file theft, persistence, lateral movement, or destructive actions on the local machine.

Session Persistence

Medium
Category
Rogue Agent
Content
1. Check for Ollama — install it if missing
2. Pull a recommended local model (Gemma 2 9B by default)
3. Copy `SKILL.md` to your OpenClaw workspace skills folder
4. Create `~/.grago/config.yaml` with sensible defaults

---
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.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
### The Trade-Off

**Risk:** If your OpenClaw agent is prompt-injected or compromised, Grago can execute arbitrary commands on your machine.

**Mitigation:**
- Grago is designed for **trusted, single-user environments** (your own Mac Mini, VPS, or workstation)
Confidence
99% confidence
Finding
The document explicitly states that the skill can execute arbitrary shell commands on the host if the upstream agent is prompt-injected or compromised. Even though this behavior is intentional and framed as part of the product design, unrestricted command execution materially expands the attack surface and can lead to full host compromise, data loss, credential theft, or persistence.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
**Safe for:** Trusted, single-user environments (your own Mac Mini, VPS, workstation)  
**NOT safe for:** Multi-tenant systems, public APIs, untrusted agents

If your OpenClaw agent is compromised via prompt injection, Grago can execute arbitrary commands. This is the trade-off for free local compute. Read `SECURITY.md` in the repo for full details.

## When to Use This Skill
Confidence
98% confidence
Finding
The skill explicitly enables shell-command execution and acknowledges that a compromised or prompt-injected agent could execute arbitrary commands. In the context of an agent skill, this creates a real remote-code-execution pathway with access to local files, network resources, and any privileges of the running user, making the surrounding context more dangerous rather than less.

External Transmission

Medium
Category
Data Exfiltration
Content
# Pipe any shell command into your local model
grago pipe \
  --fetch "curl -s https://api.example.com/data" \
  --transform "jq .results" \
  --analyze "Identify trends and flag outliers"
```
Confidence
50% 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
# Pipe any shell command into your local model
grago pipe \
  --fetch "curl -s https://api.example.com/data" \
  --transform "jq .results" \
  --analyze "Identify trends and flag outliers"
```
Confidence
50% 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
# Pipe any shell command into your local model
grago pipe \
  --fetch "curl -s https://api.example.com/data" \
  --transform "jq .results" \
  --analyze "Identify trends and flag outliers"
```
Confidence
50% 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

Medium
Confidence
95% confidence
Finding
The script claims to support 'tool-less local models', but it both fetches remote content and can transmit input to a configurable OpenAI-compatible HTTP endpoint. This mismatch is security-relevant because users may assume all processing is local and may unknowingly expose sensitive fetched or local data to external services.

External Transmission

Medium
Category
Data Exfiltration
Content
--arg user "${prompt}\n\n---\nDATA:\n${input}" \
    '{model: $model, messages: [{role: "system", content: $system}, {role: "user", content: $user}], stream: false}')
  
  curl -s "${api_base}/chat/completions" \
    -H "Content-Type: application/json" \
    -d "$payload" | jq -r '.choices[0].message.content // "Error: no response"'
}
Confidence
94% confidence
Finding
The script transmits prompts and collected data to an external HTTP endpoint using curl, which can expose sensitive or proprietary information outside the local environment. In context, this is more dangerous because the tool also aggregates data from remote sources and local files, making unintended exfiltration of mixed datasets plausible.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
Fetched data and potentially local file contents are sent to an HTTP API endpoint without explicit privacy disclosure, so sensitive information may be transmitted off-host unexpectedly. The risk is amplified by the configurable endpoint, which could point to a non-local or untrusted service despite the script's local-model framing.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Executing shell commands through --transform without clear disclosure is dangerous because users may treat it as a harmless formatting option when it is actually arbitrary code execution. This increases the chance that untrusted examples, copied commands, or generated configs will run unexpected commands on the host.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The research command permits reading arbitrary local files from paths specified in the sources YAML, which exceeds a simple web research role and can expose sensitive local data. Since the collected data is later aggregated and may be sent to a model endpoint, this broad file access materially increases exfiltration risk.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Source-level transforms in the research workflow are executed via eval with no clear warning, so a seemingly simple research configuration file can trigger arbitrary shell execution. This is particularly risky because YAML source files are likely to be shared or reused, making malicious transforms easy to hide.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The pipe command executes arbitrary shell through --fetch, which is effectively a generic command runner disguised as a data pipeline feature. Without strong disclosure, users may invoke or paste untrusted commands that can fully compromise the local environment under the user's privileges.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The pipe transform step executes arbitrary shell commands without adequate warning, creating another command-execution path that may be mistaken for benign text processing. This broadens attack surface and makes social engineering via copied command lines more effective.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The installer fetches a shell script from the network and immediately executes it with `sh` without showing the user the contents, verifying integrity, or requiring explicit confirmation. This creates a direct remote code execution path: if the remote server, DNS, TLS trust chain, or delivery path is compromised, arbitrary commands will run on the user's machine during installation.

Session Persistence

Medium
Category
Rogue Agent
Content
INSTALL_DIR="/usr/local/bin"
if [[ ! -w "$INSTALL_DIR" ]]; then
  INSTALL_DIR="$HOME/.local/bin"
  mkdir -p "$INSTALL_DIR"
fi

cp grago.sh "$INSTALL_DIR/grago"
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

Low
Confidence
88% confidence
Finding
Reading arbitrary local files from source definitions without explicit warning is a transparency and safety issue because users may not realize a research config can access host files. While file reading may be intentional in some workflows, the lack of disclosure increases the chance of accidental exposure of sensitive content.

Missing User Warnings

Low
Confidence
77% confidence
Finding
The research command writes analysis results to a user-specified file path, which is a file write operation. Although the help mentions '--output <file> Save output to file', there is no additional runtime disclosure before overwriting the target path, so the operation has only minimal warning coverage.

Static analysis

No suspicious patterns detected.