Skip to content

[Security]: Credential Cache HMAC Key Derived from Hardcoded Static String — Forgeable Key #577

Description

@hariom888

Summary

Description

In server.js (lines 52–55), the HMAC key used to derive credential-cache entries is computed as:

const _hmacKey = crypto
  .createHash("sha256")
  .update("pdf-qa-cred-cache")   // hardcoded, public string
  .digest();

This key is a deterministic SHA-256 hash of a string that is now publicly visible in the repository. The credential cache (_credCache) maps a 16-hex-character HMAC of ${sessionId}:${sessionSecret} to a { validatedAt } entry. Because the HMAC key is derived from a known constant, an attacker who knows any valid session_id (which is returned in API responses) can pre-compute the 16-character cache key for arbitrary sessionSecret values and determine whether a given (session_id, session_secret) pair is cached — a timing-oracle side-channel — without supplying the secret to the RAG service.

Steps to reproduce

Replace the static string derivation with a secret loaded from an environment variable (e.g., CRED_CACHE_HMAC_SECRET). If absent at startup, derive the key via crypto.randomBytes(32) (runtime-only — acceptable since the cache is in-memory and non-persistent). Document the env var in .env.example. Fail fast with a warning log if neither is provided in production.

Expected behavior

More concretely: by scanning the cache key space for the 16-hex-char output, an attacker with local access to the running process (e.g., a shared hosting environment, a container escape) can enumerate cached session secrets offline.

Actual behavior

  • Offline brute-force of cached session credentials is feasible because the HMAC key is constant and known.
  • The 16-character truncation of the HMAC output (64 bits) provides only ~2^64 theoretical key space, but pre-computation tables can be built for likely secret formats.

Affected Files

  • server.js lines 52–62 (_hmacKey derivation and _credKey function)

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendExpress or API gateway workbugSomething isn't workingfeatureA new feature or improvementfrontendFrontend-related worklevel:advancedrag-serviceFastAPI / model service worktype:security

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions