Skip to content

fix(db): disable Sequelize default console.log query logging to stop secret leakage to stdout#144

Merged
CryptoJones merged 1 commit into
masterfrom
fix/sequelize-disable-default-logging
May 19, 2026
Merged

fix(db): disable Sequelize default console.log query logging to stop secret leakage to stdout#144
CryptoJones merged 1 commit into
masterfrom
fix/sequelize-disable-default-logging

Conversation

@CryptoJones
Copy link
Copy Markdown
Owner

Closes #143.

Summary

Sequelize's default logging is console.log. Without overriding it, every executed SQL statement — and every bound parameter value — is dumped to stdout. That means a query like SELECT * FROM "dbo"."ApiKey" WHERE "akKey" = $1 followed by the bound array containing the raw authKey lands in stdout alongside our structured JSON output. pino's redact paths only inspect HTTP request shapes, so the Sequelize SQL path bypasses every redaction layer and the secret ends up in container logs / log shipper / retention.

Default logging: false. Operators who need query logs for targeted debugging set DB_LOG_QUERIES=1, in which case Sequelize queries are routed through pino at debug level (silent at the default LOG_LEVEL=info, visible at LOG_LEVEL=debug, never emitted as bare console.log).

Documented in .env.example with the threat-model note that the opt-in mode can still echo parameter values into the structured log.

Test plan

  • npm run lint — clean
  • npm test — 515 passed, 15 skipped (default-disabled is verified by every existing test no longer being noisy with Sequelize chatter; the opt-in path requires env var at module load, which doesn't compose well with vitest's module cache)
  • The change is a one-line behavior flip with a documented rollback (DB_LOG_QUERIES=1)

Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/

…secret leakage to stdout

Sequelize's default `logging` is `console.log`, which dumps every
executed SQL statement — INCLUDING bound parameter values — to
stdout. In production that means a query like
`SELECT * FROM "dbo"."ApiKey" WHERE "akKey" = $1` followed by the
bound array containing the raw authKey lands in the operator's log
stream alongside our structured JSON output. Two problems with that:

1. **Secret leakage**: pino's redact paths only inspect HTTP request
   shapes (`req.headers.authkey`, etc.). They never see Sequelize's
   SQL strings, so the bound authKey value bypasses every redaction
   layer and lands raw in stdout. The output goes wherever stdout
   goes — terminal in dev, Docker logs in prod, then a log shipper,
   then whatever the operator's log retention is set to.

2. **Format mixing**: structured pino JSON lines and Sequelize's
   free-form multi-line console output share the same fd. Log
   shippers (Vector, Loki, CloudWatch) that parse line-by-line as
   JSON either fail to parse the Sequelize lines or fall back to a
   "raw" representation that defeats the whole point of structured
   logging.

Default to `logging: false` — Sequelize emits nothing. Operators
who actually need query logs for debugging can set
`DB_LOG_QUERIES=1`, in which case queries route through pino at
debug level (silent at the default LOG_LEVEL=info, visible when
LOG_LEVEL=debug, and never emitted as bare console.log even when
visible).

Documented in .env.example with the threat-model note so operators
flipping it on for debugging understand it can still echo
parameter values into the structured log.

No test added: the default-disabled behavior is verified by every
existing test (no Sequelize spam in vitest output); the opt-in path
is exercised only via env var at module load, which doesn't compose
well with vitest's module cache. The change is a 1-line behavior
flip with a documented rollback (set DB_LOG_QUERIES=1).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@CryptoJones CryptoJones merged commit 7cac3a7 into master May 19, 2026
3 checks passed
@CryptoJones CryptoJones deleted the fix/sequelize-disable-default-logging branch May 19, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security(db): Sequelize default console.log dumps bound parameters (including authKey values) to stdout

1 participant