Back to skill

Security audit

brave-shim

Security checks for vulnerabilities and agentic risk

Overview

This skill clearly aims to provide a local Brave-to-DuckDuckGo search proxy, but it does so by rewriting OpenClaw's installed provider code and running unpinned third-party code and dependencies.

Review carefully before installing. Only use this in a disposable or tightly controlled OpenClaw environment, inspect and pin the brave_shim repository and Python dependencies, back up OpenClaw files before patching, and avoid sending sensitive searches or LLM context through the shim unless you trust the local service and its dependencies.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/setup_brave_shim.py:6
Finding
Unpinned Remote Repository Is Downloaded and Executed<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup_brave_shim.py:6-7, 18-22`; `scripts/start_shim.py:10-22` **Vulnerability Type**: Remote mutable payload retrieval and execution **Risk Level**: High ### Complete Code Snippet From `scripts/setup_brave_shim.py`: ```python REPO_URL = "https://github.com/asoraruf/brave_shim" DEST = os.path.join(os.path.dirname(__file__), "..", "brave_shim_repo") VENV_DIR = os.path.join(DEST, "venv") def run(cmd, check=True, **kwargs): print(f"Running: {cmd}") r = subprocess.run(cmd, shell=True, **kwargs) if check and r.returncode != 0: sys.exit(f"Failed: {cmd}") return r def main(): # Clone if os.path.exists(DEST): print(f"Already exists at {DEST}, skipping clone") else: run(f'git clone {REPO_URL} "{DEST}"') ``` From `scripts/start_shim.py`: ```python def main(): shim_path = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_SHIM if not os.path.exists(shim_path): print(f"brave_shim.py not found at {shim_path}") print("Run scripts/setup_brave_shim.py first, or pass path as argument") sys.exit(1) venv_python = os.path.join(os.path.dirname(shim_path), "venv", "Scripts" if sys.platform == "win32" else "bin", "python") if not os.path.exists(venv_python): venv_python = "python" # fallback to system python print(f"Starting brave_shim from {shim_path}...") subprocess.run(f'"{venv_python}" "{shim_path}"', shell=True) ``` ### Technical Analysis The setup script clones the current state of a third-party GitHub repository without selecting an immutable commit or verifying a cryptographic digest or signature. The start script subsequently executes `brave_shim.py` from that clone. Consequently, the effective code executed by the Skill can change after the Skill itself has been reviewed. The downloaded source is not present in the audited project, so its behavior—including handling of search queries, credentials, H ...[truncated 1492 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Vendor the reviewed shim source into the Skill so the audited code is the code that executes. 2. If remote retrieval is unavoidable, pin an immutable full commit hash and verify the checked-out commit before execution. 3. Publish and verify a cryptographic checksum or signed release artifact using a trusted signing key. 4. Display the exact source revision and obtain explicit user approval before execution. 5. Run the shim with a dedicated, low-privilege account or sandbox that has no access to unrelated files, secrets, or administrative interfaces. 6. Replace shell command strings with argument arrays and disable shell processing: ```python subprocess.run( ["git", "clone", "--no-checkout", REPO_URL, DEST], check=True, ) subprocess.run( [venv_python, shim_path], check=True, shell=False, ) ``` 7. Validate any user-supplied shim path, require it to resolve inside an approved directory, and reject symbolic-link escapes. ]]>

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/patch_openclaw.py:6
Finding
OpenClaw Provider Is Hijacked by Rewriting Installed Application Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/patch_openclaw.py:6-11, 14-31` **Vulnerability Type**: Local tool and API endpoint hijacking **Risk Level**: High ### Complete Code Snippet ```python OPENCLAW_DIST = r"F:\npm\node_modules\openclaw\dist" REPLACEMENTS = { "const BRAVE_SEARCH_ENDPOINT = \"https://api.search.brave.com/res/v1/web/search\";": "const BRAVE_SEARCH_ENDPOINT = \"http://127.0.0.1:8000/res/v1/web/search\";", "const BRAVE_LLM_CONTEXT_ENDPOINT = \"https://api.search.brave.com/res/v1/llm/context\";": "const BRAVE_LLM_CONTEXT_ENDPOINT = \"http://127.0.0.1:8000/res/v1/llm/context\";", } def main(): count = 0 for fname in os.listdir(OPENCLAW_DIST): if not (fname.startswith("brave-web-search-provider") and fname.endswith(".js")): continue fpath = os.path.join(OPENCLAW_DIST, fname) content = open(fpath).read() new_content = content for old, new in REPLACEMENTS.items(): if old in new_content: new_content = new_content.replace(old, new) print(f"Patched {fname}: {old[:40]}... -> {new[:40]}...") count += 1 if new_content != content: open(fpath, "w").write(new_content) if count == 0: print("No patches applied - BRAVE_SEARCH_ENDPOINT already patched or file not found") else: print(f"Done. {count} replacement(s) made.") ``` The corresponding instructions in `SKILL.md:39-56` also direct users to replace the official Brave endpoints with the local HTTP service. ### Technical Analysis The script directly edits OpenClaw's installed JavaScript bundle, replacing the official HTTPS Brave Search and LLM-context endpoints with an unauthenticated local HTTP endpoint. This is not an isolated provider configuration: it modifies another installed application's executable code and changes the destination of legitimate-looking API calls. The local shim can observe, ...[truncated 1790 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not rewrite installed OpenClaw bundles. Use a documented custom-provider or endpoint configuration interface. 2. Limit interception to the web-search endpoint unless LLM-context proxying is explicitly required and separately approved. 3. Clearly disclose that query and context data will be sent to DuckDuckGo through third-party shim code, and obtain informed user consent. 4. Authenticate the local service and verify that the expected process owns the endpoint before changing configuration. 5. Use a dynamically allocated or configurable port to reduce collisions, and fail closed if endpoint identity cannot be established. 6. If patching is unavoidable: - Confirm the exact OpenClaw version and original file hash. - Create a protected backup. - Patch atomically. - Verify the resulting hash and exact replacements. - Provide a tested rollback operation. - Refuse to patch unexpected or already-modified files. 7. Sandbox the shim and prohibit access to unrelated files, secrets, and local services. 8. Apply explicit data minimization: strip unnecessary authorization headers, metadata, cookies, and contextual fields before proxying. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/setup_brave_shim.py:24
Finding
Runtime Installation of Unpinned Dependencies Enables Supply-Chain Substitution<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup_brave_shim.py:24-35` **Vulnerability Type**: Unpinned and unverified third-party dependencies **Risk Level**: Medium ### Complete Code Snippet ```python # Detect Python py = "python" if sys.platform == "win32" else "python3" activate = os.path.join(VENV_DIR, "Scripts" if sys.platform == "win32" else "bin", "python") # Create venv if not os.path.exists(VENV_DIR): run(f"{py} -m venv \"{VENV_DIR}\"") # Install deps pip = os.path.join(VENV_DIR, "Scripts" if sys.platform == "win32" else "bin", "pip") run(f'"{pip}" install fastapi uvicorn ddgs pyyaml') ``` The same unpinned installation command appears in `SKILL.md:27-34`: ```bash pip install fastapi uvicorn ddgs pyyaml ``` ### Technical Analysis The setup installs the latest available releases of four direct dependencies and their transitive dependency trees. There is no lockfile, version constraint, hash validation, package-index restriction, signature verification, or reproducible build metadata. A future compromised or malicious dependency release would be selected automatically. Python packages can execute code during build and installation, and later execute arbitrary logic when imported by the shim. Even absent compromise, incompatible future versions can alter behavior or introduce vulnerabilities. The package names do not demonstrate typosquatting or dependency confusion by themselves; the confirmed issue is unsafe, mutable dependency resolution. ### Attack Path 1. A direct or transitive package account, release process, or package-index distribution channel is compromised. 2. A malicious version is published and becomes the version selected by pip. 3. A user runs the setup script. 4. Pip downloads and installs the compromised package without integrity verification. 5. Malicious code executes during installation, service startup, or module import with the invoking user's privileges. ### Im ...[truncated 400 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Generate a reviewed lockfile containing exact versions for every direct and transitive dependency. 2. Require cryptographic hashes during installation, for example through a hash-locked requirements file and `pip install --require-hashes`. 3. Use an approved package index or internally mirrored repository rather than unrestricted runtime resolution. 4. Review dependency provenance, maintainers, release history, licenses, and known vulnerabilities before locking versions. 5. Run automated dependency and vulnerability scanning in the release process. 6. Build and publish a reproducible, signed artifact rather than resolving dependencies on the user's machine. 7. Execute installation and the resulting service under a dedicated, non-administrative account or sandbox. 8. Update dependencies through a controlled review process rather than automatically selecting the newest release. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (11)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
def run(cmd, check=True, **kwargs):
    print(f"Running: {cmd}")
    r = subprocess.run(cmd, shell=True, **kwargs)
    if check and r.returncode != 0:
        sys.exit(f"Failed: {cmd}")
    return r
Confidence
95% confidence
Finding
Using subprocess.run with shell=True gives the script a generic command-execution primitive, which is especially sensitive in an agent skill because the skill may be triggered in semi-automated workflows. Even if this file does not directly accept user input, the pattern enables abuse if any variable, path, or future change becomes attacker-influenced, and the setup context magnifies impact because commands install software and modify the environment.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
venv_python = "python"  # fallback to system python

    print(f"Starting brave_shim from {shim_path}...")
    subprocess.run(f'"{venv_python}" "{shim_path}"', shell=True)

if __name__ == "__main__":
    main()
Confidence
96% confidence
Finding
This is a tool-parameter abuse issue because a high-risk execution primitive is directly parameterized by external input. The skill's purpose is to configure a local proxy, so allowing runtime substitution of the executed program is more dangerous than necessary and can let an attacker pivot from benign setup to arbitrary process execution.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill instructs users to clone a repository, install packages, patch local application files, and run a local Python service, which clearly implies shell, file read, and file write capabilities. Omitting an explicit tool scope/permissions declaration makes the skill less transparent and weakens security review, increasing the chance an agent executes high-impact actions without informed consent or proper sandboxing.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill directs the user to overwrite bundled OpenClaw JavaScript files to redirect Brave API traffic to a locally hosted proxy. Modifying application distribution files is risky because it changes trusted program behavior, persists across sessions, can break updates or integrity guarantees, and creates a path for traffic interception or tampering without a prominent warning or rollback guidance.

External Transmission

Medium
Category
Data Exfiltration
Content
OPENCLAW_DIST = r"F:\npm\node_modules\openclaw\dist"
REPLACEMENTS = {
    "const BRAVE_SEARCH_ENDPOINT = \"https://api.search.brave.com/res/v1/web/search\";":
        "const BRAVE_SEARCH_ENDPOINT = \"http://127.0.0.1:8000/res/v1/web/search\";",
    "const BRAVE_LLM_CONTEXT_ENDPOINT = \"https://api.search.brave.com/res/v1/llm/context\";": 
        "const BRAVE_LLM_CONTEXT_ENDPOINT = \"http://127.0.0.1:8000/res/v1/llm/context\";",
Confidence
60% 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
OPENCLAW_DIST = r"F:\npm\node_modules\openclaw\dist"
REPLACEMENTS = {
    "const BRAVE_SEARCH_ENDPOINT = \"https://api.search.brave.com/res/v1/web/search\";":
        "const BRAVE_SEARCH_ENDPOINT = \"http://127.0.0.1:8000/res/v1/web/search\";",
    "const BRAVE_LLM_CONTEXT_ENDPOINT = \"https://api.search.brave.com/res/v1/llm/context\";": 
        "const BRAVE_LLM_CONTEXT_ENDPOINT = \"http://127.0.0.1:8000/res/v1/llm/context\";",
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The script has the ability to execute git, venv creation, and pip installation commands, which gives it broader system-modifying capability than simply toggling or configuring a local shim. In a skill context, this is more dangerous because invoking the skill causes code retrieval and package installation from external sources, creating supply-chain and execution risk beyond the stated user-facing purpose.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run(cmd, check=True, **kwargs):
    print(f"Running: {cmd}")
    r = subprocess.run(cmd, shell=True, **kwargs)
    if check and r.returncode != 0:
        sys.exit(f"Failed: {cmd}")
    return r
Confidence
96% confidence
Finding
The helper executes shell commands with shell=True, which makes command parsing depend on the shell and increases the risk of command injection if any command component becomes user-controlled or environment-influenced. In this script the current command strings are mostly constant, but they incorporate file paths and external tooling, so the pattern is still unsafe and unnecessarily expands the attack surface of a setup script that already performs network and package operations.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The implementation clones a remote GitHub repository and installs Python packages at setup time, which is remote code retrieval plus dependency installation rather than mere local proxy configuration. This is dangerous because it introduces supply-chain exposure: a compromised repository, dependency, or transient package version could result in arbitrary code execution on the host during setup or later use.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The script accepts a user-provided path and will execute whatever Python file exists there, not just the intended local brave_shim server. In a skill context, this broadens the capability from starting a known helper service to arbitrary code execution, which is especially dangerous if an agent or user can be induced to pass attacker-controlled paths.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
venv_python = "python"  # fallback to system python

    print(f"Starting brave_shim from {shim_path}...")
    subprocess.run(f'"{venv_python}" "{shim_path}"', shell=True)

if __name__ == "__main__":
    main()
Confidence
97% confidence
Finding
The script builds a shell command from variable paths and executes it with shell=True, which creates a command-injection surface. Because shim_path is taken from argv and venv_python is derived from filesystem state, an attacker who can supply or influence these values could execute arbitrary commands instead of merely launching the shim.

Static analysis

No suspicious patterns detected.