Skip to content

Defense-in-depth: API keys hashed with unsalted SHA-256 (weak crypto) #98

Description

@S3DFX-CYBER

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions