Defense-in-depth: API keys hashed with unsalted SHA-256 (weak crypto)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 48
- Forks
- 10
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 17
Description
Description
hashAPIKey computes sha256.Sum256([]byte(key)) with no per-key salt, then stores the base64-encoded digest in the plaintext apikeys.key column. Because the hash is deterministic and unsalted, a database compromise (SQLi, backup leak, insider access) lets an attacker crack all stored keys offline via rainbow tables or brute force, cracking one key is as cheap as cracking any of them. Recovered keys can then be used to authenticate as the original holder against the gateway API and downstream agent pods.
Data flow
User-supplied API key (HTTP Basic Auth password or X-API-Key header) → hashAPIKey() → SHA-256 hash without salt → stored in apikeys.key column → looked up via GatewayGetAPIKeyByHash SQL query.
Reachability
Requires prior database read access, not directly network-exploitable. Once the DB is accessed, though, every stored key can be cracked offline with no per-record computation barrier, since there's no salt. The apikeys table also stores config_id, reference_id (org ID), prefix, and name, which helps an attacker triage high-value keys.
Impact
Full API key recovery on DB compromise, enabling impersonation of any user/workflow holding a key.
Suggested fix (backward-compatible, single PR)
Switch to HMAC-SHA-256 with a server-side pepper stored outside the DB (config/K8s secret):
func hashAPIKey(key string) string {
mac := hmac.New(sha256.New, pepperKey) // pepperKey from config/K8s secret
mac.Write([]byte(key))
return base64.RawURLEncoding.EncodeToString(mac.Sum(nil))
}
This keeps the existing text column and lookup query unchanged, so it's a drop-in replacement.
A stronger option is Argon2id with a per-key salt, but that requires a DB migration and a rehash-on-next-use (or dual-read) strategy.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Locate hashAPIKey and GatewayGetAPIKeyByHash, then trace the HTTP Basic Auth and X-API-Key paths through storage in the apikeys.key column. Review how a server-side secret would be configured or supplied from a Kubernetes secret, and verify that authentication and existing lookup behavior remain covered. Done means stored keys are no longer deterministically hashed without a secret and the gateway still authenticates valid keys.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- authentication, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100