T03 · Remote Payload Retrieval and Execution
- Location
scripts/searxng_cli.py:98- Finding
Unverified Remote Installer Is Downloaded and Executed by a Shell
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This search skill is disclosed as a self-hosted SearXNG installer and CLI, but its setup path executes unverified remote code, installs mutable upstream software, creates persistence, and has unsafe shell/env handling that users should review before installing.
Install only if you are comfortable letting the skill set up and run a local SearXNG service. Review the installer first, avoid running it with sudo except for the documented symlink or directory steps you explicitly approve, pin or verify uv/SearXNG/dependencies where possible, and do not search for secrets or private data because queries may go to SearXNG and upstream search engines.
scripts/searxng_cli.py:98Unverified Remote Installer Is Downloaded and Executed by a Shell
scripts/searxng_cli.py:143Environment-Controlled Values Are Interpolated into Shell Commands
scripts/searxng_cli.py:107Installation Executes an Unpinned Upstream Repository and Dependency Set
scripts/searxng_cli.py:238Forged Localhost Trust Header and Plaintext HTTP Are Used for Configurable Destinations
The request target is built from environment-controlled host and port values and then fetched, enabling outbound requests to arbitrary local or remote destinations. In an agent skill, this can be abused for SSRF-style probing of internal services or unintended network access beyond the stated search purpose.
f"http://{SEARXNG_HOST}:{SEARXNG_PORT}",
headers=FORWARDED_FOR
)
resp = urllib.request.urlopen(req, timeout=3)
return resp.status == 200
except:
import time
Search requests are sent to a URL whose base host and port come from environment variables, allowing an attacker to redirect the client to arbitrary services. That can expose the skill as a network primitive for internal scanning or querying attacker-chosen endpoints while spoofing a trusted header.
try:
req = urllib.request.Request(url, headers=FORWARDED_FOR)
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.load(resp)
results = data.get("results", [])
The declared purpose is web search, but the documented behavior includes software installation, local configuration changes, service lifecycle management, secret generation, and process termination. This mismatch is dangerous because users or orchestrators may invoke the skill expecting low-risk search behavior while it performs privileged system administration actions with persistence and network side effects.
The declared purpose is web search, but the documented behavior includes software installation, local configuration changes, service lifecycle management, secret generation, and process termination. This mismatch is dangerous because users or orchestrators may invoke the skill expecting low-risk search behavior while it performs privileged system administration actions with persistence and network side effects.
Piping a network response directly into sh is a classic dangerous chaining pattern because it combines retrieval and execution into a single opaque step. In a skill onboarding document, this is especially risky since agents or users may run it without inspection.
# 尝试 1: curl
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
# 尝试 2: wget
This wget-to-sh pipeline has the same dangerous chaining property as the curl variant, enabling immediate execution of remotely supplied content. It reduces visibility and bypasses normal review safeguards, raising supply-chain risk.
export PATH="$HOME/.local/bin:$PATH"
# 尝试 2: wget
wget -qO- https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
# 尝试 3: 如果 PATH 未生效
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
chmod +x <skill_dir>/scripts/searxng_cli.py
# 创建 symlink(如果不存在)
which searxng-search || sudo ln -sf <skill_dir>/scripts/searxng_cli.py /usr/local/bin/searxng-search
# 设置 secret(安装时会自动生成,也可预设置)
export SEARXNG_SECRET="your-secret-key"
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
期望输出:搜索结果列表(标题 + URL + 摘要)
curl -s -H "X-Forwarded-For: 127.0.0.1" "http://127.0.0.1:8888/search?q=test&format=json" | python3 -m json.tool | head -10
期望输出:有效 JSON("query": "test" + "results": [...])
The troubleshooting guidance includes rm -rf on a path under the user's home directory. While targeted at a virtual environment, recursive forced deletion is still destructive if variables, path expansion, or copy/paste mistakes occur, and agent execution makes such mistakes more consequential.
| `connection refused` | 服务未启动 | `searxng-search start` |
| `启动失败` (install/start 超时) | 服务启动慢或端口被占用 | 等待 20-30s 后重试 `searxng-search status`;检查端口:`ss -tlnp | grep 8888` |
| 搜索返回空结果 | 所有引擎被封/超时 | 部分引擎被封属正常现象,尝试换关键词或指定引擎 `--engine brave` |
| `No module named 'xxx'` | venv 依赖缺失 | `rm -rf ~/projects/searxng/.venv && searxng-search install` |
| `Permission denied: /home/node/projects` | 目录无写入权限 | `sudo mkdir -p ~/projects && sudo chown $(whoami) ~/projects` |
| `pip: not found` (旧版 install) | uv venv 不自带 pip | 确保使用最新版 CLI 脚本(v1.2.0+,已改用 `uv pip install`) |
| 端口 8888 被占用 | 其他服务占用 | `SEARXNG_PORT=9999 searxng-search start` |
The troubleshooting guidance includes rm -rf on a path under the user's home directory. While targeted at a virtual environment, recursive forced deletion is still destructive if variables, path expansion, or copy/paste mistakes occur, and agent execution makes such mistakes more consequential.
| `connection refused` | 服务未启动 | `searxng-search start` |
| `启动失败` (install/start 超时) | 服务启动慢或端口被占用 | 等待 20-30s 后重试 `searxng-search status`;检查端口:`ss -tlnp | grep 8888` |
| 搜索返回空结果 | 所有引擎被封/超时 | 部分引擎被封属正常现象,尝试换关键词或指定引擎 `--engine brave` |
| `No module named 'xxx'` | venv 依赖缺失 | `rm -rf ~/projects/searxng/.venv && searxng-search install` |
| `Permission denied: /home/node/projects` | 目录无写入权限 | `sudo mkdir -p ~/projects && sudo chown $(whoami) ~/projects` |
| `pip: not found` (旧版 install) | uv venv 不自带 pip | 确保使用最新版 CLI 脚本(v1.2.0+,已改用 `uv pip install`) |
| 端口 8888 被占用 | 其他服务占用 | `SEARXNG_PORT=9999 searxng-search start` |
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
| `启动失败` (install/start 超时) | 服务启动慢或端口被占用 | 等待 20-30s 后重试 `searxng-search status`;检查端口:`ss -tlnp | grep 8888` |
| 搜索返回空结果 | 所有引擎被封/超时 | 部分引擎被封属正常现象,尝试换关键词或指定引擎 `--engine brave` |
| `No module named 'xxx'` | venv 依赖缺失 | `rm -rf ~/projects/searxng/.venv && searxng-search install` |
| `Permission denied: /home/node/projects` | 目录无写入权限 | `sudo mkdir -p ~/projects && sudo chown $(whoami) ~/projects` |
| `pip: not found` (旧版 install) | uv venv 不自带 pip | 确保使用最新版 CLI 脚本(v1.2.0+,已改用 `uv pip install`) |
| 端口 8888 被占用 | 其他服务占用 | `SEARXNG_PORT=9999 searxng-search start` |
The code explicitly documents and implements a bot-detection bypass by sending X-Forwarded-For: 127.0.0.1 to appear as a trusted proxy/local client. This is an intentional trust-boundary bypass and makes the skill more dangerous because it is designed to evade protections rather than merely perform search.
This helper exposes a shell-executing primitive that can be reused across commands, increasing the chance of tool parameter abuse when any input becomes attacker-controlled. In an agent skill that already performs installation and service management, such a primitive materially raises exploitation risk.
def run(cmd, check=True, cwd=None):
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, cwd=cwd)
if check and result.returncode != 0:
log(f"Error: {result.stderr}")
sys.exit(1)
The skill claims to be a search CLI but also installs software, edits configuration, launches services, stops processes, and enables persistence. This mismatch materially increases risk because invoking a seemingly simple search skill can trigger broad system changes and code execution paths users would not expect.
The installer clones a repository, creates a virtualenv, installs dependencies, and executes a remote shell installer for uv. For a search skill, this is dangerous overreach because it executes substantial unverified code and changes the host system well beyond user search functionality.
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
log("开始安装 SearXNG...")
# 1. 安装 uv
if not subprocess.run("which uv", shell=True, capture_output=True).returncode == 0:
log("安装 uv...")
run('curl -LsSf https://astral.sh/uv/install.sh | sh')
uv_path = Path.home() / ".local" / "bin" / "uv"
Piping a remotely fetched script directly into sh executes network-supplied code immediately, with no integrity verification or meaningful user warning. In an agent skill this is especially dangerous because it turns routine use into remote code execution on the host.
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
return
log("启动服务...")
env = os.environ.copy()
env["SEARXNG_SECRET"] = SEARXNG_SECRET or env.get("SEARXNG_SECRET", "devsecret")
cmd = (
This duplicate finding points to the same unsafe Popen(shell=True) sink and the same abuse path: attacker-influenced parameters can escape into shell syntax. The skill context amplifies impact because the command runs as part of service lifecycle management on the local host.
f'{SEARXNG_DIR}/.venv/bin/python -m searx.webapp '
f'--host {SEARXNG_HOST} --port {SEARXNG_PORT}'
)
subprocess.Popen(cmd, shell=True, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
import time
for _ in range(15):
This duplicate finding points to the same unsafe Popen(shell=True) sink and the same abuse path: attacker-influenced parameters can escape into shell syntax. The skill context amplifies impact because the command runs as part of service lifecycle management on the local host.
f'{SEARXNG_DIR}/.venv/bin/python -m searx.webapp '
f'--host {SEARXNG_HOST} --port {SEARXNG_PORT}'
)
subprocess.Popen(cmd, shell=True, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
import time
for _ in range(15):
The README describes search capability but does not warn users that their queries may be transmitted to a self-hosted SearXNG server and then to third-party upstream engines. This omission is risky because users may enter sensitive data under the assumption the request stays local to the agent, causing unintentional disclosure of private prompts, credentials, internal project names, or research topics.
The trigger examples are broad natural-language requests like ordinary chat queries, which increases the chance the agent will invoke the skill when the user did not explicitly intend to send a search query to this integration. In this skill's context, accidental invocation can leak user prompts or sensitive research topics to a self-hosted SearXNG instance and potentially onward to upstream search engines.
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
searxng-search-cli/
├── .claude-plugin/plugin.json
├── .codex-plugin/plugin.json
├── skills/searxng-search-cli/SKILL.md
├── SKILL.md
├── scripts/searxng_cli.py
└── references/ONBOARDING.md
The skill advertises operational capabilities that imply shell, network, environment, and file-modifying behavior, but it does not declare any explicit tool scope or permission boundary. That makes the effective trust surface opaque to users and host platforms, increasing the chance that a simple 'search' skill can unexpectedly install software, alter configuration, or invoke networked commands without informed consent.
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.
---
name: searxng-search-cli
displayName: "SearXNG Search CLI (Free, Self-hosted, Auto-deploy, Multi-Channel)"
version: 1.3.0
description: |
Use self-hosted SearXNG search engine (Free, Self-hosted, Auto-deploy, Multi-Channel). SearXNG is a free meta search engine that aggregates 200+ search engines (Google, Bing, Brave, GitHub, etc.), completely free and self-hostable.