Skip to content

fix(logger): use a constant console format string on the stack-trace path (#100) - #204

Merged
cevheri merged 2 commits into
mainfrom
fix/100-tainted-format-string
Jul 15, 2026
Merged

fix(logger): use a constant console format string on the stack-trace path (#100)#204
cevheri merged 2 commits into
mainfrom
fix/100-tainted-format-string

Conversation

@cevheri

@cevheri cevheri commented Jul 15, 2026

Copy link
Copy Markdown
Member

Part of the CodeQL triage tracked in #100 (section 2).

Problem

CodeQL js/tainted-format-string (alert 82, high): on the stack-trace path, logger.ts passed the log line as the first argument of console.error(full, "\n", safeStack). The line is sanitized against log injection (CR/LF and control chars stripped), but it still contains user-controlled text (message, context values, error message), and the first argument of a multi-argument console.* call is a format string. A %s/%d inside a user-supplied message or error text would be interpreted as a format specifier and consume the stack argument, corrupting the log record.

Fix

Pass a constant format string instead:

console.error("%s\n%s", full, safeStack);

User text now only ever appears as a formatting argument, never in the format-string position. Output is unchanged apart from no longer being reformattable by user input (verified against a real, unmocked run: %s/%d stay literal, the stack prints on its own line).

Triage context (rest of the 13 open alerts)

This was the only alert of the 13 needing a code change. The other 12 were dismissed with written justifications, per the checklist in #100:

  • 5x js/log-injection (logger.ts:96/99/102, factory.ts:58, base-provider.ts:261) - false positive: every value passes through an inline sanitizer stripping CR/LF and control chars immediately before the sink; CodeQL does not model the custom sanitizer.
  • 1x js/log-injection (logger.ts:85) - by design: the stack-trace argument is intentionally multi-line; control chars are stripped and stacks are only printed outside production.
  • 4x js/sql-injection (mssql.ts, mongodb.ts x3) - by design: Studio is a database IDE; these lines execute the user's own query/operation against their own configured connection (MSSQL via request.query with optional request.input bind parameters, MongoDB via the official driver's structured API).
  • 2x js/path-injection (sqlite.ts:176-177) - by design: the SQLite path is user-configured, trusted server-side input (documented in docs/providers/sqlite.md); NUL bytes are rejected and the path resolved; parent-dir creation is intentional first-run behavior.

Testing (TDD)

  • New failing test first: stack-trace path keeps user text out of the console format-string position - asserts the constant "%s\n%s" first argument and that user text (including literal %s/%d) lands in the arguments.
  • Two existing tests that read the log line from the first argument were updated to read it from the second (the call shape intentionally changed).

Verification

All local gates pass: format / lint / typecheck / knip / test (20 groups) / build, plus test:coverage && coverage:check (100.00%, 25753/25753 lines).

…path (#100)

CodeQL js/tainted-format-string (alert 82): the sanitized-but-user-controlled log line was passed as the first argument of console.error on the stack-trace path, so %s/%d in a user-supplied message or error text would be interpreted as format specifiers and consume the stack argument. Pass a constant "%s\n%s" format string instead; the line and the stack are now plain arguments and user text is never interpreted.
Copilot AI review requested due to automatic review settings July 15, 2026 16:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Hardens stack-trace logging against tainted format strings.

Changes:

  • Uses a constant console.error format string.
  • Updates and adds logger safety tests.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/lib/logger.ts Safely formats error lines and stacks.
tests/unit/logger.test.ts Verifies the new console call shape.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/unit/logger.test.ts Outdated
logger.error("failure", err);
expect(errorSpy).toHaveBeenCalledTimes(1);
const line = errorSpy.mock.calls[0][0] as string;
// Stack path uses a constant format string; the line is the first argument

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworded in 7c41788: the comment now states the call shape ("%s\n%s", line, stack) and that the log line is read from index 1.

Comment thread tests/unit/logger.test.ts Outdated
const err = new RangeError("out of bounds");
logger.error("bad range", err);
const line = errorSpy.mock.calls[0][0] as string;
// Stack path uses a constant format string; the line is the first argument

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworded in 7c41788: the comment now states the call shape ("%s\n%s", line, stack) and that the log line is read from index 1.

Comment thread src/lib/logger.ts Dismissed
Copilot AI review requested due to automatic review settings July 15, 2026 16:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@sonarqubecloud

Copy link
Copy Markdown

@cevheri
cevheri merged commit bacdbb2 into main Jul 15, 2026
20 checks passed
@cevheri
cevheri deleted the fix/100-tainted-format-string branch July 15, 2026 16: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.

3 participants