Skip to content

fix: security/sanitize cached git mirrors - #417

Merged
stuartwdouglas merged 4 commits into
block:mainfrom
stuartwdouglas:security/sanitize-cached-git-mirrors
Oct 28, 2026
Merged

stuartwdouglas merged 4 commits into
block:mainfrom
stuartwdouglas:security/sanitize-cached-git-mirrors

Conversation

@stuartwdouglas

Copy link
Copy Markdown
Contributor

No description provided.

@stuartwdouglas
stuartwdouglas requested a review from a team as a code owner October 28, 2026 05:19
@stuartwdouglas
stuartwdouglas requested review from joshfriend and removed request for a team October 28, 2026 05:19
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-28T06:10:16.207265Z 594b968 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3fb6908d3b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// LC_ALL=C pins git's messages to English so the filter fallback
// warning below is detectable regardless of the host locale.
cmd.Env = append(os.Environ(), "GIT_LFS_SKIP_SMUDGE=1", "LC_ALL=C")
cmd.Env = append(os.Environ(), "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL="+os.DevNull,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Clear command-scope Git config before cloning

When the cachew process is started with Git command-scope configuration via GIT_CONFIG_COUNT/GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n, os.Environ() preserves those variables and Git still applies them despite GIT_CONFIG_NOSYSTEM=1 and GIT_CONFIG_GLOBAL=/dev/null. The git(1) environment documentation says these values are added to runtime configuration and “will override values in configuration files,” so an untrusted repository can select a matching smudge/process filter in .gitattributes and execute that host command during this clone; the checkout in internal/strategy/gomod/private_fetcher.go repeats the same construction. Append GIT_CONFIG_COUNT=0 (and clear legacy command-scope config variables) so disabling file-based config actually closes this execution path.

Useful? React with 👍 / 👎.

Comment thread internal/gitclone/manager.go Outdated
Comment on lines +216 to +217
if err := repo.ConfigureMirror(ctx, clonePath); err != nil {
if removeErr := os.RemoveAll(clonePath); removeErr != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve mirrors when sanitization is canceled

When an existing mirror is first opened with a canceled or timed-out request context—such as private gomod usage without a prior DiscoverExisting pass—ConfigureMirror's Git subprocess returns the context error, but this branch treats every error as unsafe cache contents, deletes the entire valid mirror, and then returns an empty repository with no error. Propagate cancellation and other transient execution errors, reserving removal for failures that actually establish unsafe metadata, so callers retain control over failure handling.

AGENTS.md reference: AGENTS.md:L24-L25

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 05eeb4377a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread internal/strategy/git/snapshot.go Outdated
Comment on lines +149 to +150
cmd.Env = append(os.Environ(), "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL="+os.DevNull,
"GIT_CONFIG_COUNT=0", "GIT_CONFIG_PARAMETERS=", "GIT_LFS_SKIP_SMUDGE=1", "LC_ALL=C")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Clear Git templates before cloning snapshots

When cachew is launched with GIT_TEMPLATE_DIR pointing to a template containing an executable post-checkout hook, this new environment still inherits that directory. Git 2.43's git clone -h describes --template as the "directory from which templates will be used," and githooks(5) says post-checkout is also run after git clone unless --no-checkout is used; consequently this clone copies and executes the hook, then archives it under destDir/.git/hooks for clients to restore. The preceding --no-checkout clone in private_fetcher.go also copies such a hook and its subsequent checkout executes it, so force an empty template or clear GIT_TEMPLATE_DIR and disable hooks for both clone paths.

Useful? React with 👍 / 👎.

Comment thread internal/gitclone/manager.go Outdated
if refStorage != "" {
config += "\trefStorage = " + refStorage + "\n"
}
if err := os.WriteFile(configPath, []byte(config), 0o600); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Replace mirror config atomically

If cachew is terminated after the cleanup has removed the existing config, or this WriteFile leaves a partial file after an I/O failure, the mirror still retains HEAD. On the next GetOrCreate, resetMirrorMetadata fails its initial Lstat or config parse with an ordinary error rather than errUnsafeMirrorMetadata, so the broken directory is preserved and every request for that repository keeps failing instead of recloning. Write the replacement through a temporary file and rename it atomically, or classify a missing/malformed config as unsafe so interrupted sanitization is recoverable.

Useful? React with 👍 / 👎.

@stuartwdouglas stuartwdouglas changed the title Security/sanitize cached git mirrors fix: security/sanitize cached git mirrors Oct 28, 2026
@stuartwdouglas
stuartwdouglas enabled auto-merge (squash) October 28, 2026 06:04
@stuartwdouglas
stuartwdouglas merged commit 79fc919 into block:main Oct 28, 2026
7 of 8 checks passed
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