# HAXcms: Private Key Disclosure via Broken HMAC Implementation

HAXcms Node.js hmacBase64() hardcodes HMAC key "0" and appends privateKey+salt to output, leaking the signing secret via unauthenticated connectionSettings endpoint for admin JWT forgery.

- Payout: Research
- Severity: critical
- Program: HAXcms
- Found by: shreyas-challa
- Disclosed: 2026-05-19
- CVE: CVE-2026-46395
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-6c8g-9hfh-pq5h
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-6c8g-9hfh-pq5h
- Tags: area:web domain:web impact:ato impact:privesc kind:research platform:ghsa sev:critical tech:jwt tech:nodejs technique:source-review vuln:auth-bypass vuln:crypto vuln:privilege-escalation vuln:secrets-leak

**Target:** Node.js backend /system/api/connectionSettings endpoint and hmacBase64() token function
**Root cause:** hmacBase64() passes literal "0" as the HMAC key instead of the real key, and concatenates this.privateKey+this.salt onto the HMAC output before base64-encoding, so every token embeds the master signing secret in plaintext.
**Steps:**
1. GET `/system/api/connectionSettings` unauthenticated to fetch a token.
2. Base64-decode the token, discard the first 32 bytes (HMAC-SHA256 keyed with "0"), read remaining bytes as UTF-8 to obtain privateKey+salt.
3. Forge admin JWT with `JWT.sign(payload, this.privateKey+this.salt)` where payload is `{id, user: admin, iat, exp}`.
4. Also forge user_token, base_token, form_token with the same key.
5. Call authenticated admin endpoints (create/modify/delete sites, upload files) with forged tokens.
**How found:** Code review of hmacBase64() spotted the literal "0" key argument and the concatenation of this.privateKey+this.salt onto the HMAC output; compared against the correct PHP implementation (44-char vs 139+ char tokens) confirming the Node.js version leaks key material.
**Exploitation:** Single unauthenticated GET to /system/api/connectionSettings returns tokens; decode and strip 32-byte HMAC prefix to recover privateKey+salt; sign arbitrary admin JWTs and request tokens offline; use them against all authenticated endpoints for full admin control, bypassing password changes and leaving no login events.
**Escalation:** Recovered key signs every token type (JWT, user_token, site_token, form_token), giving full admin CRUD over sites, files and content without any login.
**Insight:** When auditing token/HMAC helpers, compare parallel implementations across languages in the same project: the PHP version returning only the hash versus the Node version returning hash+key is the tell. Also check token length anomalies—outputs longer than the digest size often mean appended secret material.

