Back to skill

Security audit

Openclaw Grok Search

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but it ships a non-placeholder API key and defaults users into a third-party proxy with weak credential handling.

Review before installing. Remove artifact/config.json or replace it with your own local config, rotate any exposed key, prefer GROK_API_KEY or a private config.local.json, verify the endpoint is one you trust, and avoid sending secrets, private code, personal data, or internal URLs as search queries. Pin the install source when possible.

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
config.json:2
Finding
Live API Credential Committed in Project Configuration<![CDATA[ ## Vulnerability Details **File Location**: `config.json:2-3` **Vulnerability Type**: Hardcoded plaintext API credential **Risk Level**: High ### Vulnerable Code ```json { "base_url": "https://ai.huan666.de", "api_key": "[REDACTED LIVE sk-cp-* API KEY]" } ``` The complete credential is present in the audited file. It is redacted from this report to avoid further disclosure. ### Technical Analysis The distributed `config.json` contains a non-placeholder bearer credential associated with a third-party OpenAI-compatible endpoint. This contradicts the repository's own warning in `README.md` that real API keys must not be committed. Because the runtime automatically loads `config.json`, the credential is immediately usable by anyone who downloads the project. Bearer tokens do not require additional proof of possession, so possession of this value may be sufficient to authenticate requests to the configured service. This behavior exceeds minimum privilege: a reusable shared credential does not need to be distributed for the Skill to provide search functionality. Each user should supply an independently controlled credential. ### Attack Path 1. An attacker downloads or clones the Skill package. 2. The attacker opens `config.json` and extracts the plaintext bearer token. 3. The attacker submits requests directly to the configured API endpoint using the stolen token. 4. Requests are charged against or attributed to the credential owner until the key is revoked or exhausted. 5. If the token has broader service permissions, the attacker may use every API capability authorized to that token. ### Impact Assessment An attacker can obtain the API privileges granted to the exposed token. Potential consequences include: - Unauthorized API usage. - Quota exhaustion or financial loss. - Abuse attributed to the legitimate credential owner. - Access to any additional models or operations authorized for the token. - Credential revocation and service disrup ...[truncated 177 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke and rotate the exposed API key immediately. 2. Remove the credential from the current project and all repository history. 3. Do not distribute a populated `config.json`; ship only `config.example.json` with placeholders. 4. Add `config.json` and `config.local.json` to `.gitignore`. 5. Prefer environment variables or an operating-system secret store for credential injection. 6. Add automated secret scanning to CI and pre-commit checks. 7. Issue separate credentials per user with minimum required API scope and enforce quotas. 8. Review service logs for unauthorized use of the exposed credential. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/grok_search.py:176
Finding
User Queries Are Silently Sent to a Bundled Third-Party Proxy<![CDATA[ ## Vulnerability Details **File Location**: `config.json:2-3`; `scripts/grok_search.py:176-213, 405-412` **Vulnerability Type**: Undisclosed sensitive-data transmission to a preconfigured third party **Risk Level**: High ### Vulnerable Code Bundled endpoint configuration: ```json { "base_url": "https://ai.huan666.de", "api_key": "[REDACTED LIVE API KEY]", "model": "grok-4.20-beta" } ``` Request construction and transmission: ```python url = f"{_normalize_base_url(base_url)}/v1/chat/completions" system = ( "You are a web research assistant. Use live web search/browsing when answering. " "Return ONLY a single JSON object with keys: " "content (string), sources (array of objects with url/title/snippet when possible). " "Keep content concise and evidence-backed." ) body: dict[str, Any] = { "model": model, "messages": [ {"role": "system", "content": system}, {"role": "user", "content": query}, ], "temperature": 0.2, "stream": False, } body.update(extra_body) headers: dict[str, str] = { "Content-Type": "application/json", "Authorization": f"Bearer {api_key}", } for key, value in extra_headers.items(): headers[str(key)] = str(value) req = urllib.request.Request( url=url, data=_compact_json(body).encode("utf-8"), headers=headers, method="POST", ) with urllib.request.urlopen(req, timeout=timeout_seconds) as resp: raw = resp.read().decode("utf-8", errors="replace") ``` Invocation of the request: ```python resp = _request_chat_completions( base_url=base_url, api_key=api_key, model=model, query=args.query, timeout_seconds=timeout_seconds, extra_headers=extra_headers, extra_body=extra_body, ) ``` ### Technical Analysis Network transmission is necessary for the declared web-search functionality. However, the package contains a populated `config.json`, so the normal documented invocation sends every query to the bundled `ai.huan666.de` ...[truncated 2262 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the populated `config.json` from the distributed package. 2. Require users to explicitly choose and configure an endpoint before the first request. 3. Display the destination hostname and obtain confirmation before first use. 4. Clearly document every transmitted field and the third-party data-retention implications. 5. Warn users not to include passwords, tokens, private source code, personal data, or other secrets in queries. 6. Prefer direct official API endpoints where available. 7. Provide an optional endpoint allowlist for managed environments. 8. Avoid logging query bodies or authorization headers. 9. Add a dry-run mode that displays the destination and request-field names without exposing secret values. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/configure.py:35
Finding
API Credentials Are Stored Without Explicit Permission Hardening and May Be Sent over HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/configure.py:35-39, 71`; `scripts/grok_search.py:89-94, 176` **Vulnerability Type**: Insecure local secret storage and insufficient transport validation **Risk Level**: Medium ### Vulnerable Code Configuration-path creation and plaintext credential write: ```python def default_config_path() -> Path: custom = (os.environ.get("GROK_CONFIG_PATH") or "").strip() if custom: return Path(custom).expanduser() return Path(__file__).resolve().parent.parent / "config.json" ``` ```python config_path.write_text( json.dumps(config, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", ) ``` Base URL normalization without scheme enforcement: ```python def _normalize_base_url(base_url: str) -> str: base_url = base_url.strip().rstrip("/") if base_url.endswith("/v1"): return base_url[: -len("/v1")] return base_url ``` Request URL construction: ```python url = f"{_normalize_base_url(base_url)}/v1/chat/completions" ``` ### Technical Analysis The configuration script stores the API key in plaintext using `Path.write_text()` without explicitly setting owner-only file permissions. The resulting permissions depend on the process umask, existing file mode, filesystem defaults, and platform behavior. On a shared system, another local account may be able to read the configuration. The network client also accepts an arbitrary base URL and does not require an `https` scheme. If a user, configuration file, or environment variable supplies an `http://` endpoint, the bearer credential and complete query are transmitted without TLS. An on-path attacker could read or alter the request and response. The current bundled endpoint uses HTTPS, so plaintext transport is not active under that specific configuration. The vulnerability becomes exploitable when the endpoint is overridden with an HTTP URL. Explicit validation is necessary because endpoint customization is a docume ...[truncated 1586 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create new credential files with owner-only permissions (`0600`) on POSIX systems. 2. After writing, explicitly enforce restrictive permissions with `os.chmod(config_path, 0o600)` where supported. 3. Protect against symlink-based writes by validating the destination and using secure file-creation primitives. 4. Use atomic writes through a securely created temporary file in the same directory, followed by replacement. 5. Prefer environment variables or platform credential stores instead of persistent plaintext JSON. 6. Document equivalent Windows ACL requirements and apply an owner-only ACL where feasible. 7. Parse the base URL with `urllib.parse.urlparse`. 8. Reject all schemes other than `https`. 9. If local development requires HTTP, permit it only for explicitly enabled loopback addresses such as `127.0.0.1` or `localhost`. 10. Validate that the URL contains an expected hostname and does not embed user information. 11. Never include authorization headers or complete secret-bearing URLs in error messages or logs. ]]>
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
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (14)

Tainted flow: 'timeout_seconds' from os.environ.get (line 345, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
headers=headers,
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=timeout_seconds) as resp:
        raw = resp.read().decode("utf-8", errors="replace")
        try:
            return json.loads(raw)
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented behavior promises real-time web research against a Grok-compatible endpoint and structured JSON output, but the analyzed skill content primarily describes local configuration and invocation flow without evidence of the claimed network/search implementation. This mismatch is security-relevant because users and higher-level agents may trust the skill for external verification while it may instead perform unexpected local actions or fail open in ways that conceal its true behavior.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The skill documentation is written entirely in Chinese and does not indicate that other languages are supported or provide an opt-in choice. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The README instructs users to install the skill via `npx skills add Stemmaker/openclaw-grok-search` without pinning a specific version or commit. This creates a supply-chain risk: users may receive a later modified package or dependency set than the one reviewed, and if the upstream package or referenced repo is compromised, arbitrary code could be installed or executed during setup.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill advertises executable behavior that involves shell, file access, environment-variable use, and network activity, but it declares no explicit tool scope or permissions boundaries. In an agent ecosystem, this increases the chance of unintended execution with broader privileges than users or orchestrators expect, especially because the skill is project-local and instructs direct command execution.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The activation rule 'You are uncertain and need external confirmation' is overly broad and can cause the skill to run in many routine situations, expanding the frequency of shell execution, config access, and network use. Broad triggering makes benign prompts more likely to invoke a higher-risk capability without strong necessity, increasing exposure to prompt-induced tool use and unnecessary data handling.

Session Persistence

Medium
Category
Rogue Agent
Content
## Quick Start

1. Write config interactively (first run only).

```bash
python scripts/configure.py
Confidence
78% confidence
Finding
The skill instructs users to write configuration interactively and persist it in local project files, creating session persistence that may store API keys or endpoint settings beyond the immediate task. Persistent local secrets and settings increase the risk of later disclosure, misuse by other tools in the workspace, or accidental inclusion in version control.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script interactively collects an API key and persists it in plaintext JSON on disk without any explicit warning, masking, or permission hardening. This increases the chance that a user unknowingly stores sensitive credentials in a project directory that may be copied, backed up, shared, or committed to version control, leading to credential disclosure and misuse of the Grok endpoint.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The skill can automatically execute a separate local script when configuration is missing, creating an implicit code-execution path that may surprise users and increase risk if the skill directory or configure.py is tampered with. In an agent context, auto-running helper scripts is more dangerous because installation paths, repositories, or local files may not always be trusted.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
sys.stderr.write("configure.py not found; cannot auto-configure.\n")
        return False
    try:
        run([sys.executable, configure_path], check=True)
    except CalledProcessError:
        sys.stderr.write("configure.py failed; aborting.\n")
        return False
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code sends the user-provided query to a remote OpenAI-compatible endpoint and also allows arbitrary extra headers and body fields to be transmitted. While the behavior is central to the script's purpose, there is no explicit user-facing notice in the code that query contents and configured metadata will be sent over the network.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
Allowing arbitrary caller-supplied headers lets a caller override or inject security-relevant HTTP metadata, including Authorization, Host, or proxy-related headers, which can redirect trust or exfiltrate credentials to unintended endpoints. In this skill, that risk is amplified because the same request carries the API key and user query to a configurable remote service.

Context-Inappropriate Capability

Low
Confidence
84% confidence
Finding
The manifest presents a focused web research/search tool returning content and sources, but the implementation accepts arbitrary extra JSON merged into the outbound API body. This broadens the effective remote capability beyond the declared search workflow by allowing callers to enable undocumented model/provider-specific features.

Missing User Warnings

Low
Confidence
85% confidence
Finding
The script reads API credentials from environment variables or config files and uses them for outbound authentication, but the code provides no explicit warning or documentation comment about credential handling. This can matter for auditing and operator awareness, especially when credentials are sourced from local config files.

Static analysis

No suspicious patterns detected.