Somebody left the search bar plugged straight into the database, and now any logged-in user can clog the drain
CVE-2026-25591 is a SQL LIKE wildcard injection in the /api/token/search endpoint of QuantumNous/new-api, an open-source, self-hosted LLM gateway written in Go. Versions prior to 0.10.8-alpha.10 concatenate user-supplied keyword and token parameters directly into LIKE '%' + input + '%' clauses in model/token.go:70 without escaping % or _ wildcards. An authenticated user can inject patterns like %_%_%_%_%_% to force the database to scan every row. With ~2 million tokens in the database, a single request consumed 200 MB+ of RAM and 6 seconds of database CPU, leading to connection-pool exhaustion and service unavailability for all downstream AI consumers.
The vendor's CVSS 3.1 score of 6.5 MEDIUM (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H) is mechanically correct — network-reachable, low-complexity, authenticated, availability-only. However, it *slightly overstates* real-world urgency for most shops. The authentication gate means random internet scanners cannot exploit this; you need a valid API token issued by the gateway admin. The software is self-hosted and niche (popular in the open-source AI community at ~49k GitHub stars but not a standard enterprise fixture), and the DoS is recoverable with a service restart. There is no public PoC, no known exploitation, and no KEV listing. A reassessed score of 5.0 MEDIUM better reflects the operational risk for a team managing 10,000 hosts where maybe a handful run this gateway.
4 steps from start to impact.
Obtain authenticated access
- Valid API token or authenticated session on the New API instance
- Tokens are admin-issued; random internet attackers cannot self-register unless the instance is misconfigured with open registration
- Most deployments sit behind a reverse proxy on an internal network, not exposed to the public internet
Craft malicious LIKE wildcard pattern
%_%_%_%_%_% or a long string of % characters. No special tooling is needed — this is a single HTTP parameter. The pattern forces the database engine into a full-table scan with expensive per-row pattern matching.- Knowledge that the
/api/token/searchendpoint exists and acceptskeywordortokenparameters
- The endpoint and parameter names are documented in the open-source codebase, so this is trivial for anyone who reads the repo — but it also means the fix is equally visible
Send crafted request to /api/token/search
/api/token/search?keyword=%_%_%_%_%_%. Each request triggers an unescaped LIKE query against the tokens table. With a sufficiently large token table (~2M rows), each query takes ~6 seconds and consumes 200 MB+ of application memory.- Network reachability to the New API HTTP endpoint
- Token table large enough to produce meaningful resource consumption
- Small or personal deployments with hundreds or low thousands of tokens will see negligible impact — the DoS scales linearly with dataset size
- Rate limiting at the reverse proxy or application layer blocks repeated requests
LIKE queries. Application performance monitoring (APM) will show memory and CPU spikes correlated with the search endpoint.Service denial achieved
- Sustained request volume sufficient to overwhelm connection pool (dependent on instance sizing and concurrency limits)
- Restarting the service or killing the offending database queries restores availability immediately
- A simple query timeout configuration (5-second limit) prevents any single query from monopolizing resources
/api/token/search endpoint at 30 requests/minute per authenticated user. This prevents the sustained request volume needed to exhaust database resources. No noisgate mitigation SLA applies for MEDIUM verdicts — go straight to the 365-day remediation window, but this control is cheap and should be deployed within a week as good hygiene.max_execution_time, PostgreSQL statement_timeout, SQLite pragma) to kill any query exceeding 5 seconds. This caps the damage from any single wildcard-injection request and prevents connection-pool exhaustion. Apply alongside rate limiting for defense in depth.% and _ wildcards before interpolation into LIKE clauses. This is within the noisgate remediation SLA of ≤365 days for MEDIUM, but given the trivial upgrade path (single Docker image tag change for most deployments), aim to complete within 30 days.- WAF wildcard-pattern rules — the malicious payload is just
%and_characters in a search parameter, which are legitimate search characters in normal use. Writing a WAF rule that blocks%in query strings will break legitimate search functionality without meaningfully reducing risk. - Disabling the search endpoint entirely — while this would eliminate the attack surface, it removes legitimate token-management functionality that administrators rely on. Not a viable long-term control.
- Network-level DDoS protection (Cloudflare, AWS Shield) — these tools mitigate volumetric/L3-L4 attacks, not application-layer resource exhaustion from authenticated API calls. The attack bypasses all network-layer protections because it looks like a normal authenticated HTTP request.
The supporting signals.
| In-the-wild exploitation | None observed. No reports from threat-intel feeds, vendor advisories, or security vendors indicate active exploitation of this CVE. |
|---|---|
| Proof-of-concept | No public PoC. The advisory by researchers xuemian168 and callmeiks includes a detailed writeup with timing data (5,973–6,200 ms queries on 2M tokens), but no standalone exploit script has been published on GitHub or exploit databases. |
| EPSS | 0.00644 (0.644%) — 49th percentile. Below the median exploitation probability; consistent with a DoS-only bug requiring authentication. |
| KEV status | Not listed. CISA KEV does not include this CVE. No federal mandate to patch. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H (6.5 MEDIUM). CVSS v4.0 scored at 7.1 HIGH (AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N). The discrepancy is mechanical — v4.0 weights authenticated availability-only bugs slightly higher. |
| Affected versions | All versions of QuantumNous/new-api prior to 0.10.8-alpha.10. The vulnerable code is in model/token.go:70. |
| Fixed version | 0.10.8-alpha.10 — the fix escapes % and _ wildcard characters before interpolation into LIKE clauses. Patch authored by Calcium-Ion. |
| Scanning / exposure | No Shodan or Censys dork specifically fingerprints New API instances. Broader LLM gateway exposure research (GreyNoise, Jan 2026) found 42,665 exposed AI agent instances across many products, but New API's specific share is undocumented. Most self-hosted Go deployments sit behind reverse proxies with no distinguishing banner. |
| Disclosure date | 2026-02-24 — coordinated disclosure via GitHub Security Advisory GHSA-w6x6-9fp7-fqm4. |
| Reporters | xuemian168 and callmeiks, with remediation by Calcium-Ion (QuantumNous maintainer). |
Sources.
Why this verdict
- Authentication gate narrows the attacker pool: PR:L means the attacker needs a valid token issued by the gateway admin. This eliminates drive-by exploitation and mass-scanning campaigns. In a well-run deployment, token issuance is controlled and auditable — reducing the reachable attacker population to insiders or compromised-credential holders.
- Impact ceiling is DoS only: C:N/I:N means no data exfiltration, no code execution, no lateral movement. The worst outcome is temporary unavailability of the AI gateway. The DoS is recoverable with a service restart or query kill — no persistent damage.
- Niche self-hosted software with limited enterprise footprint: At ~49k GitHub stars, New API is popular in the open-source AI community but is not a standard enterprise component. Most enterprises managing 10,000 hosts will have zero or single-digit instances. This sharply limits the blast radius across a typical fleet.
- No exploitation evidence or public PoC: EPSS at 0.644% (49th percentile), no KEV listing, no known campaigns, no weaponized exploit code. The theoretical attack is documented but nobody is using it.
- DoS impact scales with dataset size: The advisory's worst-case numbers (6-second queries, 200 MB per request) assume 2 million tokens in the database. Smaller deployments — the majority — will see proportionally less impact.
- Role multiplier: New API is an LLM gateway — it routes AI API requests and manages tokens/costs. (a) *Low-value role:* personal AI proxy or dev sandbox — DoS is a minor annoyance, restart fixes it. (b) *Typical role:* team/department LLM access hub — DoS disrupts AI-assisted workflows for a team, recoverable in minutes. (c) *High-value role:* enterprise-wide AI gateway fronting all LLM providers for production AI features — DoS blocks AI-dependent services fleet-wide, but the blast radius is 'AI services down,' NOT 'domain takeover / fleet compromise / mass data egress / supply-chain pivot.' This component does not appear in the canonical high-value-role catalog (not an IdP, DC, hypervisor, CI/CD, backup, DB engine, EDR, network edge, SIEM, or OT controller). The floor rule does not engage because no high-value-role outcome reaches the threshold.
Why not higher?
The vulnerability is DoS-only with no path to code execution, privilege escalation, or data exfiltration. It requires authentication, which is already a significant narrowing of the attacker population. The affected software is a niche open-source project, not a canonical high-value infrastructure component, and there is zero exploitation evidence. Elevating to HIGH would overstate urgency and misallocate patching resources away from bugs that actually enable compromise.
Why not lower?
The vulnerability is real and network-reachable with low complexity. A single authenticated request can consume 200 MB+ of memory and 6 seconds of CPU — repeating this can take down the entire AI gateway, affecting every downstream consumer. The fix is a one-line wildcard escape, meaning the vendor left a genuinely avoidable flaw in a security-sensitive endpoint. Dropping to LOW would understate the availability impact for organizations that depend on this gateway for production AI workloads.
Crowdsourced verification payload.
Run this on the host where New API is deployed, or from any machine that can reach the New API HTTP endpoint. Requires curl and jq. Invoke as: bash check_cve_2026_25591.sh https://your-new-api-host:3000. No special privileges required — it queries the unauthenticated /api/status endpoint for version information.
#!/usr/bin/env bash
# check_cve_2026_25591.sh — Detect CVE-2026-25591 (SQL LIKE Wildcard Injection DoS)
# Usage: bash check_cve_2026_25591.sh <NEW_API_BASE_URL>
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
BASE_URL="${1:-}"
if [ -z "$BASE_URL" ]; then
echo "Usage: $0 <NEW_API_BASE_URL>"
echo "Example: $0 https://ai-gateway.internal:3000"
exit 2
fi
# Strip trailing slash
BASE_URL="${BASE_URL%/}"
# Try to get version from /api/status
RESPONSE=$(curl -sf --max-time 10 "${BASE_URL}/api/status" 2>/dev/null || true)
if [ -z "$RESPONSE" ]; then
echo "UNKNOWN — could not reach ${BASE_URL}/api/status"
echo "Verify the URL and that the New API instance is running."
exit 2
fi
# Extract version string (e.g., "0.10.8-alpha.10")
VERSION=$(echo "$RESPONSE" | jq -r '.data.version // .version // empty' 2>/dev/null || true)
if [ -z "$VERSION" ]; then
echo "UNKNOWN — /api/status responded but version field not found."
echo "Response: $RESPONSE"
echo "Manual check: verify version >= 0.10.8-alpha.10 in your deployment config."
exit 2
fi
echo "Detected New API version: $VERSION"
# Parse version components
# Fixed version is 0.10.8-alpha.10
# We need to compare: major.minor.patch-prerelease
FIXED_MAJOR=0
FIXED_MINOR=10
FIXED_PATCH=8
FIXED_PRE=10
# Extract major.minor.patch
MAJOR=$(echo "$VERSION" | grep -oP '^\d+' || echo "0")
MINOR=$(echo "$VERSION" | grep -oP '^\d+\.\K\d+' || echo "0")
PATCH=$(echo "$VERSION" | grep -oP '^\d+\.\d+\.\K\d+' || echo "0")
# Extract alpha prerelease number if present
PRE=$(echo "$VERSION" | grep -oP 'alpha\.\K\d+' || echo "999")
# Compare versions
if [ "$MAJOR" -gt "$FIXED_MAJOR" ]; then
echo "PATCHED — version $VERSION is newer than fixed version 0.10.8-alpha.10."
exit 0
elif [ "$MAJOR" -eq "$FIXED_MAJOR" ] && [ "$MINOR" -gt "$FIXED_MINOR" ]; then
echo "PATCHED — version $VERSION is newer than fixed version 0.10.8-alpha.10."
exit 0
elif [ "$MAJOR" -eq "$FIXED_MAJOR" ] && [ "$MINOR" -eq "$FIXED_MINOR" ] && [ "$PATCH" -gt "$FIXED_PATCH" ]; then
echo "PATCHED — version $VERSION is newer than fixed version 0.10.8-alpha.10."
exit 0
elif [ "$MAJOR" -eq "$FIXED_MAJOR" ] && [ "$MINOR" -eq "$FIXED_MINOR" ] && [ "$PATCH" -eq "$FIXED_PATCH" ]; then
# Same base version — check prerelease
if echo "$VERSION" | grep -qP 'alpha'; then
if [ "$PRE" -ge "$FIXED_PRE" ]; then
echo "PATCHED — version $VERSION includes the fix for CVE-2026-25591."
exit 0
else
echo "VULNERABLE — version $VERSION is below the fixed version 0.10.8-alpha.10."
echo "Upgrade to 0.10.8-alpha.10 or later."
exit 1
fi
else
# 0.10.8 release (no alpha) is newer than 0.10.8-alpha.10
echo "PATCHED — version $VERSION is a release newer than 0.10.8-alpha.10."
exit 0
fi
else
echo "VULNERABLE — version $VERSION is below the fixed version 0.10.8-alpha.10."
echo "Upgrade to 0.10.8-alpha.10 or later."
exit 1
fi