# GHSA-hjwh-xvfw-qrwj: SearXNG Basic Authentication Credentials Exposed Through MCP Logs and JSON-RPC Error Responses

> An attacker with log access or MCP client connectivity can recover SearXNG Basic Authentication credentials exposed in logs and error responses.

- **Severity:** Not scored
- **Exploited in the wild:** Not known
- **Login needed:** Not needed
- **Attackable:** Local or same network only
- **Victim action needed:** Not needed
- **Fix available:** Yes
- **Published:** 19 Aug 2026

## What is GHSA-hjwh-xvfw-qrwj?

GHSA-hjwh-xvfw-qrwj is a vulnerability in mcp-searxng, published on 19 Aug 2026. It can only be exploited from the same machine or local network, with no action from the victim.

### Official description

### Summary

mcp-searxng version 1.11.0 exposes SearXNG Basic Authentication credentials embedded in the `SEARXNG_URL` environment variable.

When the server starts in STDIO mode and an MCP client connects, the complete `SEARXNG_URL`, including its username and password, is sent to the client through an MCP `notifications/message` logging notification.

Additionally, when URL validation fails, the complete credential-bearing URL is included in the configuration error. This error is logged through MCP and returned to the client as a JSON-RPC error response.

For example, a value such as:

```text
http://username:password@searxng.example.com
```

is exposed without redaction.

A connected MCP client or anyone with access to captured server logs may recover the SearXNG credentials and use them to access the configured SearXNG instance.

The issue was confirmed in:

```text
mcp-searxng 1.11.0
```

Suggested severity: **Medium**

### Details

mcp-searxng supports SearXNG Basic Authentication by embedding credentials in the URL userinfo component:

```text
https://username:password@searxng.example.com
```

The project contains a redaction function named `redactSearxngInstanceUrl()`, but it is not used in several logging and error-handling paths.

#### Startup console disclosure

In `src/index.ts:373-378`, the server retrieves the raw SearXNG URLs and writes them directly to stderr:

```typescript
const searxngInstances = getSearxngInstances();

if (searxngInstances.length > 0) {
  console.error(`🌐 SearXNG URLs: ${searxngInstances.join("; ")}`);
}
```

`getSearxngInstances()` returns the unmodified environment-variable values.

Relevant code in `src/searxng-instances.ts:25-38`:

```typescript
export function parseSearxngUrls(
  raw: string | undefined = process.env.SEARXNG_URL
): string[] {
  if (raw === undefined) {
    return [];
  }

  return raw
    .split(";")
    .map((entry) => entry.trim())
    .filter((entry) => entry !== "");
}

export function getSearxngInstances(): string[] {
  return parseSearxngUrls();
}
```

#### MCP logging notification disclosure

After the MCP client connects, `src/index.ts:388-393` sends the complete URL through the MCP logging interface:

```typescript
const searxngInstances = getSearxngInstances();

logMessage(
  mcpServer,
  "info",
  `SearXNG URLs: ${
    searxngInstances.length > 0
      ? searxngInstances.join("; ")
      : "not configured"
  }`
);
```

`logMessage()` passes this value to `sendLoggingMessage()` in `src/logging.ts:15-25`:

```typescript
mcpServer.sendLoggingMessage({
  level,
  data: notificationData
});
```

As a result, the connected MCP client receives a message containing the username and password:

```json
{
  "method": "notifications/message",
  "params": {
    "level": "info",
    "data": {
      "message": "SearXNG URLs: http://username:password@searxng.example.com"
    }
  },
  "jsonrpc": "2.0"
}
```

#### Configuration error disclosure

The URL validation function includes the complete unredacted value in error messages.

Relevant code in `src/searxng-instances.ts:44-52`:

```typescript
export function validateSearxngInstanceUrl(
  value: string
): string | null {
  try {
    const url = new URL(value);

    if (!["http:", "https:"].includes(url.protocol)) {
      return `SEARXNG_URL invalid protocol for "${value}": ${url.protocol}`;
    }
  } catch {
    return `SEARXNG_URL invalid format: ${value}`;
  }

  return null;
}
```

The validation error is aggregated by `validateEnvironment()` in `src/error-handler.ts:175-203`:

```typescript
const validationError =
  validateSearxngInstanceUrl(searxngUrl);

if (validationError) {
  issues.push(validationError);
}
```

The complete error is then thrown from `src/search.ts:689-693`:

```typescript
const validationError = validateEnvironment();

if (validationError) {
  logMessage(mcpServer, "error", "Configuration invalid");
  throw new MCPSearXNGError(validationError);
}
```

The tool handler in `src/index.ts:254-260` sends the error message and stack trace through MCP logging, then rethrows it:

```typescript
logMessage(
  mcpServer,
  "error",
  `Tool execution error: ${
    error instanceof Error
      ? error.message
      : String(error)
  }`,
  {
    tool: name,
    args: args,
    error:
      error instanceof Error
        ? error.stack
        : String(error)
  }
);

throw error;
```

Rethrowing the error causes the same unredacted credential-bearing URL to be returned in the JSON-RPC error response.

#### Existing redaction function is not used

The project already contains a suitable redaction function in `src/searxng-instances.ts:57-69`:

```typescript
export function redactSearxngInstanceUrl(
  raw: string
): string {
  try {
    const url = new URL(raw);

    if (!url.username && !url.password) {
      return raw;
    }

    url.username = "";
    url.password = "";
    return url.toString();
  } catch {
    return raw.replace(
      /^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)[^/]*@/,
      "$1"
    );
  }
}
```

However, this function is not applied before startup logging, MCP logging, or configuration error construction.

The MCP manifest also marks `SEARXNG_URL` as non-secret in `.mcp/server.json:20-25`:

```json
{
  "name": "SEARXNG_URL",
  "description": "URL of your SearXNG instance",
  "isRequired": true,
  "isSecret": false,
  "format": "string"
}
```

Because credentials may be embedded in this variable, it should be classified as a secret.

### PoC

The following proof of concept uses fake credentials. A real SearXNG server is not required.

#### Requirements

```text
Node.js 20 or newer
npm
mcp-searxng 1.11.0 source code
```

#### Build the application

```bash
unzip mcp-searxng-main.zip
cd mcp-searxng-main

npm ci
npm run build
```

#### Test 1: Credential disclosure through MCP logging

Create an MCP initialization request:

```bash
cat > /tmp/mcp-init.jsonl <<'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"credential-leak-poc","version":"1.0.0"}}}
EOF
```

Start the server with fake credentials embedded in a valid HTTP URL:

```bash
SEARXNG_URL='http://MCP_POC_USER_7391:MCP_POC_PASS_7391@127.0.0.1:9' \
timeout 8s node dist/cli.js \
< /tmp/mcp-init.jsonl \
2>&1 | tee credential-log-leak.txt
```

Search the output for the credentials:

```bash
grep -nE \
'MCP_POC_USER_7391|MCP_POC_PASS_7391' \
credential-log-leak.txt
```

#### Observed result

The complete credential-bearing URL is exposed:

```text
SearXNG URLs: http://MCP_POC_USER_7391:MCP_POC_PASS_7391@127.0.0.1:9
```

It is also delivered to the MCP client:

```json
{
  "method": "notifications/message",
  "params": {
    "level": "info",
    "data": {
      "message": "SearXNG URLs: http://MCP_POC_USER_7391:MCP_POC_PASS_7391@127.0.0.1:9"
    }
  },
  "jsonrpc": "2.0"
}
```

This confirms that a connected MCP client can recover the configured username and password without accessing the host environment.

#### Test 2: Credential disclosure through JSON-RPC errors

Create initialization and tool-call requests:

```bash
cat > /tmp/mcp-error-poc.jsonl <<'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"credential-error-poc","version":"1.0.0"}}}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"searxng_web_search","arguments":{"query":"credential leak test"}}}
EOF
```

Start the server with a credential-bearing URL that uses an unsupported protocol:

```bash
SEARXNG_URL='ftp://MCP_POC_USER_7391:MCP_POC_PASS_7391@example.invalid' \
timeout 8s node dist/cli.js \
< /tmp/mcp-error-poc.jsonl \
2>&1 | tee credential-error-leak.txt
```

Search the response:

```bash
grep -nE \
'MCP_POC_USER_7391|MCP_POC_PASS_7391' \
credential-error-leak.txt
```

#### Observed result

The complete URL is exposed in the MCP logging notification:

```text
Tool execution error: Configuration Issues: SEARXNG_URL invalid protocol

## Which versions are affected by GHSA-hjwh-xvfw-qrwj?

2 open source packages ship an affected version, including mcp-searxng.


| Package | Ecosystem | Affected | Fixed in |
| --- | --- | --- | --- |
| `mcp-searxng` | npm | All versions | 1.12.0 |
| `mcp-searxng` | npm | All versions | 1.12.0 |

## How do I fix GHSA-hjwh-xvfw-qrwj?

Upgrade mcp-searxng to 1.12.0 or later.

## Is GHSA-hjwh-xvfw-qrwj being exploited?

There is no known exploitation of GHSA-hjwh-xvfw-qrwj in the wild and no public exploit code.

## Fix prompt for AI coding agents

```text
Check this codebase for GHSA-hjwh-xvfw-qrwj and fix it if it is affected.

What it is: GHSA-hjwh-xvfw-qrwj is a vulnerability in mcp-searxng, published on 19 Aug 2026. It can only be exploited from the same machine or local network, with no action from the victim.
Exploitation: There is no known exploitation of GHSA-hjwh-xvfw-qrwj in the wild and no public exploit code.

Affected packages and fixed versions:
- mcp-searxng (npm): affected all versions; fixed in 1.12.0
- mcp-searxng (npm): affected all versions; fixed in 1.12.0

Task:
1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.
2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.
3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.
4. Run the tests and summarise what changed and why.
5. If nothing in the project is affected, say so and change nothing.

Reference: https://insights.sbomify.com/GHSA-hjwh-xvfw-qrwj/ (Markdown: https://insights.sbomify.com/GHSA-hjwh-xvfw-qrwj/index.md)
```

## Sources

- OSV: https://osv.dev/vulnerability/GHSA-hjwh-xvfw-qrwj

---
From sbomify Insights: https://insights.sbomify.com/GHSA-hjwh-xvfw-qrwj/
Summaries are generated and may contain mistakes; the official description above is the record.
