A burglar who can only rob a house during the thirty seconds the front door is propped open on move-in day
CVE-2026-50160 is a mass-assignment flaw (CWE-915) in the self-hosted Hoppscotch backend ≤ 2026.4.1. The POST /v1/onboarding/config endpoint accepts arbitrary key-value pairs because the global NestJS ValidationPipe is configured without whitelist: true. When usersCount === 0 — i.e., *before the very first admin finishes initial setup* — an unauthenticated attacker can inject JWT_SECRET and SESSION_SECRET into the database, seize the signing key, and forge admin tokens at will. The fix in 2026.5.0 enables whitelist: true and forbidNonWhitelisted: true, stripping undeclared properties before they reach the service layer.
The vendor CVSS of 10.0 is technically defensible for a freshly-deployed, internet-facing, un-onboarded instance — that exact scenario really is unauthenticated RCE-equivalent with changed scope. But that scenario is a vanishingly narrow slice of reality. The exploit only works during a window measured in *minutes to hours* between docker compose up and the admin completing setup. Hoppscotch is an API-development tool (a Postman alternative), not core infrastructure. Most self-hosted instances sit behind a VPN or on an internal network, and the moment the first admin account is created the endpoint is dead. Calling every Hoppscotch deployment a CVSS 10 emergency misrepresents the actual fleet risk to defenders.
4 steps from start to impact.
Locate a fresh, internet-exposed Hoppscotch instance
usersCount === 0. This is a race condition: the window closes once the admin creates the first account.- Instance is network-reachable from attacker
- Instance is in onboarding state (usersCount === 0)
- Most self-hosted Hoppscotch instances live behind a VPN or firewall, not on the public internet
- The onboarding window is minutes to hours — automated mass-scanning rarely catches it
- Hoppscotch's installed base of self-hosted instances is small relative to infrastructure software
Confirm onboarding status
GET /v1/onboarding/status returns whether onboarding is complete. If the response indicates the instance is unconfigured, the attacker proceeds. No authentication is required for this check.- Onboarding status endpoint returns 'not completed'
- If an admin has already completed setup (even partially with a user account), this returns completed and the chain dies
/v1/onboarding/status should trigger alerting.Inject JWT_SECRET via mass assignment
POST /v1/onboarding/config with the legitimate onboarding fields *plus* injected keys like JWT_SECRET and SESSION_SECRET. Because the ValidationPipe lacks whitelist: true, the extra keys pass through to the service layer, which iterates Object.entries(dto) and writes all keys to the InfraConfig table. The attacker now controls the JWT signing key.- Endpoint accepts POST without authentication
- ValidationPipe does not strip extra properties
- Single HTTP request — trivial if you reach the endpoint
- PoC is public (GBHackers, Offgrid Security blog, nuclei template)
/v1/onboarding/config from external sources. Database audit logging on InfraConfig table writes.Forge admin JWT and take over the instance
JWT_SECRET, the attacker crafts a valid JWT for any user, including the admin account (or creates one). This grants full administrative access to the Hoppscotch instance — read/write all workspaces, extract stored API keys and tokens, modify shared collections.- Attacker knows the JWT_SECRET they injected
- At least one admin user exists or attacker completes onboarding themselves
- Standard JWT forgery — trivial with
jsonwebtokenorjwt.io
/v1/onboarding/* from external sources. No mitigation SLA applies for MEDIUM — go straight to the 365-day remediation window, but this firewall rule should be baseline hygiene deployed immediately.usersCount === 0. Ensure deployment runbooks include mandatory immediate onboarding completion — ideally automated via a post-deploy script that creates the first admin account. Once onboarding completes, the endpoint is inert. This is a process control, not a technical patch, but it eliminates the attack surface entirely.whitelist: true and forbidNonWhitelisted: true to the global NestJS ValidationPipe, stripping undeclared properties. Current release is 2026.7.0. No mitigation SLA applies at MEDIUM — apply within the 365-day noisgate remediation window..env or database InfraConfig table, then restart the backend service.- WAF virtual patching alone — while a WAF rule blocking POST to
/v1/onboarding/confighelps, it only works if the WAF is in the traffic path. Many internal Hoppscotch deployments don't sit behind a WAF, and the rule must be in place *before* deployment, not after. - Rate limiting — the onboarding endpoint already has rate limiting, but the exploit requires only a single request. Rate limiting does not mitigate single-shot attacks.
- Network segmentation without port blocking — segmenting Hoppscotch into a dev VLAN doesn't help if the VLAN is reachable by other internal users who could be compromised or malicious. The onboarding endpoint needs explicit access control, not just network zoning.
The supporting signals.
| In-the-wild exploitation | No evidence of active exploitation. Not listed in CISA KEV. No campaign reporting from Mandiant, CrowdStrike, or DFIR sources as of October 2026. |
|---|---|
| Proof of concept | Public and trivial. Full curl-based PoC published by GBHackers and Offgrid Security. A Nuclei template exists in projectdiscovery/nuclei-templates. The exploit is a single POST request — no tooling required beyond curl. |
| EPSS | 0.01701 (1.70%) — low predicted exploitation probability. Consistent with narrow attack surface. |
| KEV status | Not listed. No CISA KEV entry as of 2026-10-09. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N — 10.0. The vector is accurate *for the exact scenario* of an exposed, un-onboarded instance. The S:C (Changed scope) reflects JWT compromise enabling cross-boundary impact. |
| Affected versions | Hoppscotch self-hosted backend ≤ 2026.4.1 (all prior versions). Cloud/SaaS (hoppscotch.io) is not affected. |
| Fixed version | 2026.5.0 — adds whitelist: true and forbidNonWhitelisted: true to global ValidationPipe. Current release is 2026.7.0. |
| Scanning / exposure | No dedicated Shodan/GreyNoise tag for Hoppscotch backend. The default port 3170 is not commonly scanned. Hoppscotch has ~79,200 GitHub stars but self-hosted enterprise deployments are a small fraction — most users use the SaaS or browser extension. |
| Disclosure date | 2026-07-01 via GitHub Security Advisory GHSA-j542-4rch-8hwf. Fix shipped same day in 2026.5.0. |
| Researcher | Discovered by Kira, an autonomous security AI agent built by Offgrid Security. Reporter credited as infycore. Fix PR #6171. |
Sources.
- GitHub Security Advisory GHSA-j542-4rch-8hwf
- GBHackers — Critical Hoppscotch Vulnerability Analysis
- Offgrid Security — Kira Finds CVSS 10.0 in Hoppscotch
- CyberPress — Critical Hoppscotch Flaw
- NVD — CVE-2026-50160
- ProjectDiscovery Nuclei Templates (includes CVE-2026-50160)
- Hoppscotch Self-Host Documentation
- OpenCVE — CVE-2026-50160
Why this verdict
- Onboarding-only window eliminates persistent exposure. The endpoint is only exploitable when
usersCount === 0— a transient state lasting minutes to hours after initial deployment. Once the first admin completes setup, the attack surface vanishes entirely. This is not a standing vulnerability; it's a deployment-race condition. - Self-hosted-only scope drastically limits the population. The SaaS version (hoppscotch.io) is unaffected. Self-hosted Hoppscotch is a niche deployment — most of the 79K GitHub-star user base uses the hosted version or the browser extension. The fraction of enterprise fleets running self-hosted Hoppscotch backend is very small.
- Internal network placement is the norm. Self-hosted Hoppscotch instances are typically deployed on internal networks behind VPNs or firewalls for team API development. Internet-facing exposure of the backend port (3170) is uncommon and unnecessary for normal use.
- EPSS corroborates low real-world risk. At 1.70%, the predicted exploitation probability is low, consistent with the narrow preconditions.
- Role multiplier: Hoppscotch is NOT a high-value-role component. It is a developer productivity tool (API client), not identity infrastructure, not a hypervisor, not a CI/CD pipeline, not a network edge appliance. Compromise of a Hoppscotch instance yields access to stored API collections and potentially cached credentials — this is *data exposure at the tool level*, not domain takeover, fleet compromise, or supply-chain pivot. The blast radius is bounded to the Hoppscotch instance and any API keys stored within it. No high-value-role floor applies.
- No active exploitation or threat actor interest. Three months post-disclosure, no KEV listing, no campaign reporting, no DFIR case studies. The EPSS and absence of ITW activity confirm this is not being weaponized at scale.
Why not higher?
The PoC is public and trivial (single curl), the endpoint requires zero authentication, and a compromised instance leaks any stored API credentials — these factors prevent dropping below MEDIUM. If Hoppscotch were commonly internet-exposed, this would remain HIGH or CRITICAL. The raw technical severity of JWT signing-key takeover is real; it's the deployment context that narrows it.
Why not lower?
The exploit *is* unauthenticated and trivial when preconditions are met. Stored API keys and OAuth tokens in Hoppscotch workspaces could include production credentials, creating a potential pivot path. A public nuclei template means automated scanning will find any exposed instance in the onboarding window. Dropping to LOW would understate the risk for the (admittedly small) population of internet-facing fresh deployments.
Crowdsourced verification payload.
Run this script on any host that can reach the Hoppscotch backend (e.g., your auditor workstation or a jump box on the same network). Pass the target URL as the first argument: bash check_cve_2026_50160.sh http://hoppscotch-host:3170. No special privileges required — it only makes GET requests.
#!/usr/bin/env bash
# check_cve_2026_50160.sh — CVE-2026-50160 Hoppscotch Mass Assignment Check
# Usage: bash check_cve_2026_50160.sh <BASE_URL>
# Example: bash check_cve_2026_50160.sh http://10.0.1.50:3170
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
set -euo pipefail
BASE_URL="${1:-}"
if [[ -z "$BASE_URL" ]]; then
echo "Usage: $0 <HOPPSCOTCH_BACKEND_URL>"
echo "Example: $0 http://localhost:3170"
exit 2
fi
# Strip trailing slash
BASE_URL="${BASE_URL%/}"
echo "[*] Checking CVE-2026-50160 against $BASE_URL"
# Step 1: Check if the backend is reachable
HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 "$BASE_URL/" 2>/dev/null || true)
if [[ -z "$HTTP_CODE" || "$HTTP_CODE" == "000" ]]; then
echo "[!] Cannot reach $BASE_URL"
echo "UNKNOWN"
exit 2
fi
echo "[*] Backend reachable (HTTP $HTTP_CODE)"
# Step 2: Check onboarding status (the key risk indicator)
ONBOARD_RESP=$(curl -s --connect-timeout 5 "$BASE_URL/v1/onboarding/status" 2>/dev/null || true)
if [[ -z "$ONBOARD_RESP" ]]; then
echo "[!] Could not query onboarding status endpoint"
echo "UNKNOWN"
exit 2
fi
echo "[*] Onboarding status response: $ONBOARD_RESP"
# Step 3: Parse onboarding completion status
# If onboarding is NOT complete and usersCount is 0, the instance is actively vulnerable
if echo "$ONBOARD_RESP" | grep -qiE '"(is_setup_done|isSetupDone|completed)"\s*:\s*false'; then
echo "[!] Onboarding is NOT complete — endpoint is exploitable!"
echo ""
echo "VULNERABLE"
echo ""
echo "ACTION: Complete onboarding immediately or block external access."
echo " Then upgrade to Hoppscotch >= 2026.5.0."
exit 1
fi
if echo "$ONBOARD_RESP" | grep -qiE '"(is_setup_done|isSetupDone|completed)"\s*:\s*true'; then
echo "[*] Onboarding is complete — endpoint is no longer exploitable."
echo "[*] NOTE: You should still upgrade to >= 2026.5.0 to fix the"
echo " underlying mass-assignment flaw for future redeployments."
echo ""
# Check if we can infer version
# Try the config endpoint to see if whitelist is enforced (patched behavior)
PROBE_CODE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 \
-X POST "$BASE_URL/v1/onboarding/config" \
-H 'Content-Type: application/json' \
-d '{"__noisgate_probe": "test"}' 2>/dev/null || true)
if [[ "$PROBE_CODE" == "400" || "$PROBE_CODE" == "422" ]]; then
echo "[*] Probe returned $PROBE_CODE — ValidationPipe likely rejects unknown properties (patched)."
echo "PATCHED"
exit 0
elif [[ "$PROBE_CODE" == "401" || "$PROBE_CODE" == "403" ]]; then
echo "[*] Probe returned $PROBE_CODE — endpoint requires auth (patched or onboarding gated)."
echo "PATCHED"
exit 0
else
echo "[*] Probe returned $PROBE_CODE — cannot confirm patch status."
echo "[*] Verify you are running Hoppscotch >= 2026.5.0 manually."
echo "UNKNOWN"
exit 2
fi
fi
echo "[!] Could not parse onboarding status response."
echo "UNKNOWN"
exit 2