Skip to content

fix(core): stop leaking secrets into debug output (GHSA-28pg-v3hp-9g7f) - #383

Merged
gregberge merged 3 commits into
mainfrom
fix/debug-secret-redaction
Sep 13, 2026
Merged

gregberge merged 3 commits into
mainfrom
fix/debug-secret-redaction

Conversation

@gregberge

@gregberge gregberge commented Sep 13, 2026

Copy link
Copy Markdown
Member

Fixes GHSA-28pg-v3hp-9g7f.

DEBUG=@argos-ci/core is the documented way to diagnose an upload, and its output is pasted into public issues and written to CI logs. Two sinks printed live credentials:

  • getCiEnvironment() logged the whole process.env snapshot — GITHUB_TOKEN, the OIDC request token, and any secret a project defines itself;
  • upload() logged its parameters and the resolved config, both carrying the ARGOS_TOKEN repository token.

Fix

The environment is no longer logged. getCiEnvironment() logs that detection is running, and No CI service matched when it comes up empty; when a service does match, the next line already logs the resolved ciEnvironment — commit, branch, repository, pull request — which is what the output is read for. Nothing to allowlist, nothing to leak.

The token is masked, and logged once. resolveArgosToken() logs its first six characters (Authenticated with ARGOS_TOKEN (92d832…)) — enough to answer "is that the token I think it is?" when an upload lands on the wrong project, useless to anyone reading a public CI log. That is the one place that knows which token the command ends up using, whether it came from the parameters or the environment, so it is logged there instead of being repeated by every object that carries it: upload() strips it from the parameters and from the resolved config, the way deploy() and uploadMedia() already did.

Tests

src/upload.test.ts drives the advisory's own PoC through the real upload(): with the namespace enabled, the token never appears in what the logger writes to stderr, and the masked prefix does. It fails on main.

🤖 Generated with Claude Code

`DEBUG=@argos-ci/core` is the documented way to diagnose an upload, and its
output is pasted into public issues and written to CI logs. It printed the whole
`process.env` snapshot while detecting the CI environment — `GITHUB_TOKEN`, the
OIDC request token and any secret a project defines itself — while the upload
path printed its parameters and the resolved config, both carrying the
`ARGOS_TOKEN` repository token.

Redact in the logger rather than at each call site: every argument is copied
with its credential-looking properties replaced before it reaches the debug
package, so no caller has to remember which of its fields is a secret. The
environment snapshot keeps the values of the variables CI detection reads, minus
the credentials among them, and reduces every other variable to its name — which
is what a "why wasn't my CI detected?" report needs, and leaks nothing the
project defined itself.

The hand-written token stripping in `deploy` and `uploadMedia` is the logger's
job now, so it goes away.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
argos-js-sdk-reference Ready Ready Preview Sep 13, 2026 9:22am UTC

Request Review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Prefix-based environment allowlisting can still expose arbitrary secrets, and object getters can make debug logging alter runtime behavior.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Centralizes debug-log credential redaction and sanitizes CI environment output.

Changes:

  • Adds recursive secret and environment redaction.
  • Applies redaction centrally in the debug logger.
  • Adds regression tests and removes caller-side token stripping.
File summaries
File Description
packages/core/src/redact.ts Implements redaction helpers.
packages/core/src/redact.test.ts Tests redaction behavior.
packages/core/src/debug.ts Redacts enabled debug output.
packages/core/src/debug.test.ts Verifies logger-level token removal.
packages/core/src/ci-environment/index.ts Sanitizes environment diagnostics.
packages/core/src/deploy.ts Delegates parameter redaction to logger.
packages/core/src/media.ts Delegates parameter redaction to logger.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/core/src/redact.ts Outdated
Comment thread packages/core/src/redact.ts Outdated
Allowlisting CI variables by prefix still printed whatever a project names
`GITHUB_*`, `CI_*` or `ARGOS_*` itself, secrets included. Rather than maintain
an exact list of the variables the detectors read, drop the environment from the
debug log altogether: when a service matches, the next line already logs the
resolved CI environment — commit, branch, repository, pull request — which is
what the output is read for. A "no CI service matched" line takes over what the
dump was worth when nothing matched.

`redactSecrets` stays, covering the other sink: the upload parameters and the
resolved config, both carrying `ARGOS_TOKEN`. It now walks property descriptors
instead of `Object.entries`, so turning the debug flag on never calls a caller's
getter — `util.inspect` renders an accessor as `[Getter]` without invoking it,
and a getter that throws no longer takes the upload down with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hing

With the environment no longer logged, the only credential left reaching the
debug output is the Argos token, and it gets there through three flat objects —
not enough to justify a logger that walks every argument it is handed. Drop
`redact.ts` and strip the token where it is logged, the way `deploy` and
`uploadMedia` already did.

The token is still worth seeing: "is that the token I think it is?" is a real
question when an upload lands on the wrong project. `resolveArgosToken` now logs
its first six characters — enough to recognize it, useless to anyone reading a
public CI log. That is also the one place that knows which token the command
ends up using, whether it came from the parameters or from the environment, so
it is logged once there instead of being repeated by every object carrying it.

Add a regression test driving the advisory's own PoC through `upload()`: the
token never appears in the debug output, the masked prefix does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gregberge gregberge changed the title fix(core): redact secrets from debug output (GHSA-28pg-v3hp-9g7f) fix(core): stop leaking secrets into debug output (GHSA-28pg-v3hp-9g7f) Sep 13, 2026
@gregberge
gregberge merged commit cd59273 into main Sep 13, 2026
74 checks passed
@gregberge
gregberge deleted the fix/debug-secret-redaction branch September 13, 2026 11:17
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.

2 participants