From abff545aa8a1691c95bb376a6a70330ede119eef Mon Sep 17 00:00:00 2001 From: L4XB Date: Thu, 22 Oct 2026 23:13:01 +0200 Subject: [PATCH] fix(hooks): redact Docker's auth values in activity summaries A raw Docker configuration, as `cat ~/.docker/config.json` prints it, keeps its credential under `"auth":`, which only the auth_config name matched. Count `auth` as a credential word when it ends the word, so `"auth":`, `AUTH=` and `oauth=` are redacted while `author` and `auth_method` are not. --- scripts/hooks/session-activity-tracker.js | 11 ++++++----- tests/hooks/session-activity-tracker.test.js | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/hooks/session-activity-tracker.js b/scripts/hooks/session-activity-tracker.js index 626ad2dbc..e2167486a 100644 --- a/scripts/hooks/session-activity-tracker.js +++ b/scripts/hooks/session-activity-tracker.js @@ -41,11 +41,12 @@ function redactSecrets(value) { // The rest covers what governance-capture detects, since tool output such as // `cat .env` lands in these summaries too. // A name that carries a credential word anywhere (`AWS_SECRET_ACCESS_KEY`, - // `DOCKER_AUTH_CONFIG`), but not `max_tokens` or `tokenizer`. The name parts - // around the word are bounded, which keeps long output linear. A quoted value - // may hold escaped quotes; a JSON value can hold spaces, so one that opens with - // { or [ is redacted to the end; a bare value ends at the next field. - .replace(/\b([\w.-]{0,64}(?:secret|token(?!s|iz)|passw(?:or)?d|api[_-]?key|access[_-]?key|private[_-]?key|credential|auth[_-]?config)[\w.-]{0,64})(["']?\s*[:=]\s*)(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[{[].*|[^\s,;}\]"']+)/gi, '$1$2') + // `DOCKER_AUTH_CONFIG`, Docker's `"auth":`), but not `max_tokens`, `tokenizer` + // or `author`. The name parts around the word are bounded, which keeps long + // output linear. A quoted value may hold escaped quotes; a JSON value can hold + // spaces, so one that opens with { or [ is redacted to the end; a bare value + // ends at the next field. + .replace(/\b([\w.-]{0,64}(?:secret|token(?!s|iz)|passw(?:or)?d|api[_-]?key|access[_-]?key|private[_-]?key|credential|auth\b|auth[_-]?config)[\w.-]{0,64})(["']?\s*[:=]\s*)(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[{[].*|[^\s,;}\]"']+)/gi, '$1$2') .replace(/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g, '') .replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----.*/g, '') .replace(/\bgh[pousr]_[A-Za-z0-9_]+\b/g, '') diff --git a/tests/hooks/session-activity-tracker.test.js b/tests/hooks/session-activity-tracker.test.js index cf813d4db..9d1df6b22 100644 --- a/tests/hooks/session-activity-tracker.test.js +++ b/tests/hooks/session-activity-tracker.test.js @@ -518,6 +518,8 @@ function runTests() { assert.strictEqual(summarizeOutput('AWS_SECRET_ACCESS_KEY=example-secret-value'), 'AWS_SECRET_ACCESS_KEY='); assert.strictEqual(summarizeOutput('DOCKER_AUTH_CONFIG={"auths":{"registry":{}}}'), 'DOCKER_AUTH_CONFIG='); assert.strictEqual(summarizeOutput('DOCKER_AUTH_CONFIG={"auths": {"registry": {"auth": "dXNlcjpwYXNz"}}}'), 'DOCKER_AUTH_CONFIG='); + assert.strictEqual(summarizeOutput('{"auths":{"registry":{"auth":"dXNlcjpwYXNz"}}}'), '{"auths":{"registry":{"auth":}}}'); + assert.strictEqual(summarizeOutput('auth_method=oidc author=Jane'), 'auth_method=oidc author=Jane'); assert.strictEqual(summarizeOutput('{"token": "abc.def", "user": "bob"}'), '{"token": , "user": "bob"}'); const jwt = ['eyJ' + 'a'.repeat(12), 'eyJ' + 'b'.repeat(12), 'c'.repeat(12)].join('.'); assert.strictEqual(summarizeOutput(`Bearer ${jwt} done`), 'Bearer done');