Back to skill

Security audit

SearXNG Self-Host

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for self-hosted search, but its installer uses root privileges to fetch mutable third-party code and enable a persistent service, so it needs Review before use.

Install only on a machine where you are comfortable granting root-level setup authority and running a persistent local search service. Review or modify the installer to pin and verify SearXNG, uv, and dependencies before production use, and avoid sending sensitive prompts or internal identifiers as searches because fallback mode sends queries to Wikipedia and GitHub.

Vulnerability Patterns
  • 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
  • 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 (1)

T08 · Insecure Dependencies

Error
Location
scripts/install_searxng.sh:14
Finding
Unpinned Third-Party Code and Dependency Installation with Root Privileges<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install_searxng.sh:14-35` **Vulnerability Type**: Unpinned and unverified third-party dependencies **Risk Level**: High ### Vulnerable Code ```bash echo "[1/6] Installing system dependencies..." apt-get update -qq apt-get install -y -qq git python3-pip # Install uv via pip if not present if ! command -v uv &>/dev/null; then pip3 install -q uv --break-system-packages fi echo "[2/6] Creating searxng user and directories..." id -u $SEARXNG_USER &>/dev/null || /usr/sbin/useradd -r -d $SEARXNG_HOME -s /bin/false $SEARXNG_USER mkdir -p $SEARXNG_HOME chown $SEARXNG_USER:$SEARXNG_USER $SEARXNG_HOME echo "[3/6] Cloning SearXNG..." if [ -d "$SEARXNG_HOME/searxng-src" ]; then echo " Already cloned — skipping" else git clone https://github.com/searxng/searxng "$SEARXNG_HOME/searxng-src" --depth=1 fi echo "[4/6] Installing dependencies with uv..." cd "$SEARXNG_HOME/searxng-src" uv venv "$SEARXNG_HOME/searx-venv" --python python3 uv pip install --python "$SEARXNG_HOME/searx-venv/bin/python" \ -r "$SEARXNG_HOME/searxng-src/requirements.txt" ``` ### Technical Analysis The installer is documented to run as root, but it downloads and installs mutable third-party components without pinning or integrity verification: - `pip3 install uv` resolves the latest available version rather than a reviewed version. - `--break-system-packages` modifies the operating system’s managed Python environment, increasing the potential scope of dependency conflicts or compromise. - `git clone` retrieves the current default branch of SearXNG without selecting a reviewed commit, immutable release tag, or signed release. - Dependencies are installed from the newly downloaded `requirements.txt` without a locally reviewed lock file or enforced hashes. - No checksum, signature, commit allowlist, or provenance verification is performed. Consequently, the code executed or installed by this script can change after the Skill its ...[truncated 1945 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `uv` to a reviewed, explicit version and require package hashes during installation. 2. Avoid `--break-system-packages`; install bootstrap tooling in a dedicated virtual environment or use a verified OS package. 3. Pin SearXNG to an immutable, reviewed commit or a verified signed release rather than cloning the current default branch. 4. Verify the downloaded source using a trusted signature or an expected SHA-256 digest before installation. 5. Maintain a reviewed dependency lock file with exact versions and cryptographic hashes. Enforce hash verification during dependency installation. 6. Prefer building an immutable package or container in a controlled CI environment, generating an SBOM, scanning dependencies, and deploying the verified artifact. 7. Separate privileged setup from unprivileged dependency installation. Create system directories and the service account with root, but download and build application dependencies under the dedicated `searxng` account where practical. 8. Harden the systemd unit with controls such as `NoNewPrivileges=true`, `PrivateTmp=true`, `ProtectSystem=strict`, `ProtectHome=true`, and a narrowly scoped `ReadWritePaths=` declaration after verifying application requirements. 9. Document the exact installed release and provide an explicit, verified update procedure instead of implicitly accepting changing upstream content on each fresh installation. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (8)

External Script Fetching

High
Category
Supply Chain
Content
Verify:
```bash
curl 'http://127.0.0.1:8888/search?q=test&format=json' | python3 -m json.tool | head -20
systemctl status searxng
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
Verify:
```bash
curl 'http://127.0.0.1:8888/search?q=test&format=json' | python3 -m json.tool | head -20
systemctl status searxng
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill instructs users to perform network and shell actions, including installation and service management, but does not declare any tool scope such as permissions or allowed-tools. In an agent setting, this creates an authorization gap where powerful capabilities may be invoked without explicit restriction or review, increasing the chance of unintended command execution or network access.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
## Installation (new instance)

Run as root on Ubuntu 22.04/24.04:

```bash
bash scripts/install_searxng.sh
Confidence
87% confidence
Finding
The skill explicitly tells the operator to run installation as root, which is a privileged execution path. While software installation often requires elevated privileges, embedding root-level execution in a broadly reusable agent skill increases risk if the referenced script is modified, misused, or triggered in the wrong environment, since any mistake would have full system impact.

Session Persistence

Medium
Category
Rogue Agent
Content
EOF

systemctl daemon-reload
systemctl enable searxng
systemctl restart searxng

echo ""
Confidence
80% 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.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The script silently falls back from a local SearXNG instance to direct requests to Wikipedia and GitHub, which transmits user queries to external third parties. In an agent context, queries may contain sensitive prompts, internal identifiers, or operational data, so this behavior can violate expected data-boundary assumptions even though it is framed as resilience logic.

External Transmission

Medium
Category
Data Exfiltration
Content
def search_github(query, count=5):
    """GitHub Search API - 10 req/min unauthenticated"""
    url = f"https://api.github.com/search/repositories?q={urllib.parse.quote(query)}&per_page={count}"
    req = urllib.request.Request(url, headers={**HEADERS, 'Accept': 'application/vnd.github.v3+json'})
    try:
        with urllib.request.urlopen(req, timeout=8) as r:
Confidence
90% confidence
Finding
The GitHub API request sends search queries to an external service, creating a direct outbound data flow. In this skill's context, the danger is elevated because users may expect a self-hosted/local search path, while agent-generated queries can include sensitive internal terms that should not be disclosed to third parties.

Intent-Code Divergence

Low
Confidence
77% confidence
Finding
The top-level docstring presents 'Primary' and 'Fallback' backends as if they are part of the general search behavior, but the implementation only invokes the direct APIs conditionally after a SearXNG failure. This is a documentation-to-code mismatch about operational behavior, not just missing detail.

Static analysis

No suspicious patterns detected.