Skip to content

fix(git): redact URL credentials in GitError message, argv, and stderr - #562

Merged
goosewobbler merged 1 commit into
mainfrom
fix/git-error-token-redaction
Jul 19, 2026
Merged

goosewobbler merged 1 commit into
mainfrom
fix/git-error-token-redaction

Conversation

@goosewobbler

@goosewobbler goosewobbler commented Jul 19, 2026 •

Copy link
Copy Markdown
Owner

What

Mask user:password@ userinfo in any URL embedded in a GitError's message, args, and stderr, at the constructor choke point in @releasekit/git.

Why

When git.httpsTokenEnv is configured, the push remote is an authenticated URL (https://x-access-token:<token>@github.com/…). On any push failure (e.g. a branch-protection ruleset rejection), that URL rode the failed argv — and git's own stderr — into GitError.message, which propagates into PipelineError → the failure-report PR comment (world-readable on public repos) and CI logs. GitHub's log masking doesn't apply to comment bodies, so the token was disclosed.

How

  • redactUrlCredentials() does a linear (no-backtracking) scan over scheme://userinfo@ spans and replaces the userinfo with ***.
  • Applied in the GitError constructor so every construction site is covered without each caller remembering. The array handed to the runner is untouched (a redacted copy is stored), so the real push still uses the real URL.
  • Catches the token whether it rides the argv or git echoes the URL in stderr.

Tests

  • End-to-end: a push failure with an authenticated remote yields a GitError whose message/args/stderr contain no token and show https://***@github.com/o/r.git.
  • Unit: redactUrlCredentials masks user:pass@ spans and leaves credential-free / scp-style remotes intact.

Closes #557

Greptile Summary

This PR fixes a credential-disclosure vulnerability where authenticated HTTPS remote URLs were leaking into GitError.message, .args, and .stderr, which propagate to the failure-report PR comment and CI logs.

  • Introduces redactUrlCredentials(text) using a linear regex anchored on the literal :// that replaces the userinfo segment with ***, avoiding ReDoS via a negated character class instead of a quantified scheme prefix.
  • Applies redaction centrally in the GitError constructor so all construction sites are covered without per-caller changes; the real args array passed to the runner is left untouched so the live push still uses the real URL.
  • Adds an end-to-end test asserting redaction across all three fields on a push failure, plus unit tests covering multi-occurrence strings, credential-free URLs, scp-style remotes, and a 200 k-character adversarial input for linearity.

Confidence Score: 5/5

Safe to merge — the change is a well-scoped security fix applied at a single constructor choke point with no changes to the live call path.

The regex is intentionally linear (negated character class anchored on ://, no alternation or nested quantifiers), is applied in the GitError constructor so every call site is covered automatically, and the real args array handed to the runner is untouched. Tests cover end-to-end push failure redaction, multi-URL strings, credential-free URLs, scp-style remotes, and the adversarial-length input. No defects found.

No files require special attention.

Important Files Changed

Filename Overview
packages/git/src/errors.ts Adds redactUrlCredentials and wires it into the GitError constructor; regex is linear, handles all tested credential formats, and correctly excludes / to respect the authority boundary.
packages/git/test/unit/git.spec.ts Adds targeted tests for credential redaction on push failure and unit tests for the regex; coverage includes multi-URL strings, no-credential URLs, scp-style remotes, and the ReDoS guard.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Runner as GitRunner
    participant GitCli as GitCli.push()
    participant GitError as GitError constructor
    participant Caller as Caller / PipelineError

    GitCli->>Runner: run(['push','--', authenticatedRemoteUrl, ...])
    Runner-->>GitCli: throws exec error (exit 128, stderr with URL)
    GitCli->>GitError: new GitError(message, args, exitCode, stderr)
    Note over GitError: redactUrlCredentials applied to message, each arg, and stderr
    GitError-->>Caller: "GitError with credentials replaced by ***"
    Note over Caller: Token never reaches PR comment or CI logs
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Runner as GitRunner
    participant GitCli as GitCli.push()
    participant GitError as GitError constructor
    participant Caller as Caller / PipelineError

    GitCli->>Runner: run(['push','--', authenticatedRemoteUrl, ...])
    Runner-->>GitCli: throws exec error (exit 128, stderr with URL)
    GitCli->>GitError: new GitError(message, args, exitCode, stderr)
    Note over GitError: redactUrlCredentials applied to message, each arg, and stderr
    GitError-->>Caller: "GitError with credentials replaced by ***"
    Note over Caller: Token never reaches PR comment or CI logs
Loading

Reviews (2): Last reviewed commit: "fix(git): redact URL credentials in GitE..." | Re-trigger Greptile

@github-actions

github-actions Bot commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor

Standing release PR: #555 · v0.40.1 queued (4 packages) · open 1h 21m · ✅ ready to merge

Release Preview — v0.40.0 → v0.40.1

Note: Labels on this PR are advisory in standing-pr mode. Bumps come from conventional commits in the standing PR; override by editing labels on the standing PR itself. Add release:immediate to bypass the standing PR and release this PR directly.

These changes will be added to the release PR (#555) when merged:

Changelog

monorepo 0.40.0 → 0.40.1

Fixed

  • redact URL credentials in GitError message, argv, and stderr (git)

All packages → 0.40.1 (sync versioning)

  • @releasekit/version
  • @releasekit/notes
  • @releasekit/publish
  • @releasekit/release

After merge — predicted release

No version escalation — this PR's changes will be included in the queued release without affecting the projected versions.

Package Standing PR This PR After merge
monorepo 0.40.1 0.40.1 0.40.1

Updated automatically by ReleaseKit

Comment thread packages/git/src/errors.ts Fixed
An authenticated push/fetch remote (https://x-access-token:<token>@github.com/…)
rode the failed argv — and git's own stderr — into GitError, which surfaces in CI
logs and the failure-report PR comment on any push failure. Mask the user:password
userinfo at the GitError construction choke point so every construction site is
covered; the array handed to the runner is untouched, so the real push still uses
the real URL.

Refs #557

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011i1KvoyxATU3bz5V5Sf1Xu
@goosewobbler
goosewobbler force-pushed the fix/git-error-token-redaction branch from 78fa7bf to 95ba88f Compare July 19, 2026 15:26
@goosewobbler
goosewobbler merged commit 4a51135 into main Jul 19, 2026
18 checks passed
@goosewobbler
goosewobbler deleted the fix/git-error-token-redaction branch July 19, 2026 17:28
This was referenced Jul 19, 2026
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.

GitHub push token leaks into the failure-report PR comment and CI logs on push failure

2 participants