Summary
The Copilot CLI's @github/copilot package (v1.0.49, distributed via npm and also bundled with the GitHub Copilot Chat VS Code extension) unconditionally mutates the host process's process.env at SDK initialization to inject a Git hardening setting:
GIT_CONFIG_COUNT=<n+1>
GIT_CONFIG_KEY_<n>=safe.bareRepository
GIT_CONFIG_VALUE_<n>=explicit
Because process.env is the process-wide environment, this propagates to every child process spawned from that host for its lifetime. When the host is VS Code's extension host (the Copilot Chat extension bundles @github/copilot and loads ./sdk), this includes:
- Debuggee processes launched via "Run / Debug"
- Tests launched via Test Explorer (C# Dev Kit, etc.)
- VS Code tasks
- Tools/CLIs invoked from extensions, chat, or the integrated terminal
Any of those that perform Git operations against bare repositories — a legitimate, common pattern (SwiftPM caches, bare clones, server-side mirrors, tooling that creates ephemeral bare repos) — then fail with:
fatal: cannot use bare repository '<path>' (safe.bareRepository is 'explicit')
even though the user's own Git configuration says all (or is unset, which defaults to all). There is no UI for this, no setting to opt out, and from the affected process's point of view the change is invisible — git config --get safe.bareRepository in the user's own shell still returns all because the override is only carried through GIT_CONFIG_* env vars inherited from the SDK host process tree.
Where
The package source isn't published in this repo, so the evidence is from the shipped artifact:
<vscode>/Contents/Resources/app/extensions/copilot/node_modules/@github/copilot/sdk/index.js (the same @github/copilot 1.0.49 that's on npm), minified function:
function bHt() {
let t = parseInt(process.env.GIT_CONFIG_COUNT || "0", 10),
e = Number.isFinite(t) && t >= 0 ? t : 0,
r = Math.min(e, 64);
for (let n = 0; n < r; n++)
if (process.env[`GIT_CONFIG_KEY_${n}`] === "safe.bareRepository" &&
process.env[`GIT_CONFIG_VALUE_${n}`] === "explicit") return;
process.env.GIT_CONFIG_COUNT = String(e + 1);
process.env[`GIT_CONFIG_KEY_${e}`] = "safe.bareRepository";
process.env[`GIT_CONFIG_VALUE_${e}`] = "explicit";
}
Invoked from the SDK module's top-level init (ky = A(() => { ...; bHt(); ... })), so the mutation happens as soon as the SDK is imported.
If linkable source exists in an internal repo, please update the report — I could only verify against the minified bundle.
Versions
@github/copilot 1.0.49 (also installable standalone via npm i -g @github/copilot)
- Observed via Visual Studio Code 1.122.1, GitHub Copilot Chat extension 0.50.1 (bundles the SDK)
Repro (standalone, no VS Code required)
# A Node process that imports the SDK leaks the env vars to its children:
node -e "import('@github/copilot/sdk').then(() => { \
console.log('COUNT=', process.env.GIT_CONFIG_COUNT); \
for (let i = 0; i < Number(process.env.GIT_CONFIG_COUNT||0); i++) \
console.log(i, process.env['GIT_CONFIG_KEY_'+i], '=', process.env['GIT_CONFIG_VALUE_'+i]); \
const { execSync } = require('child_process'); \
execSync('mkdir -p /tmp/bare-repro && git -C /tmp/bare-repro init --bare && git -C /tmp/bare-repro branch test', { stdio: 'inherit' }); \
});"
Expected (post-mutation):
COUNT= 1
0 safe.bareRepository = explicit
fatal: cannot use bare repository '/tmp/bare-repro' (safe.bareRepository is 'explicit')
In VS Code, the same symptom appears in any debuggee/test process the extension host spawns. git config --show-origin --show-scope --get-all safe.bareRepository inside that process reports command command line: explicit (i.e. it came from the inherited GIT_CONFIG_* env triple, not from any config file).
Impact
Why this is a scope problem
safe.bareRepository=explicit is a personal hardening preference. Git positions it as something a user opts into in their own global config because they personally don't use bare repositories. The SDK silently applying it to the entire host process (and therefore to every child the user spawns from that host) is a global policy change the user did not opt into, cannot opt out of, and cannot even see without inspecting process.env. Even users who never call any Git-touching Copilot API are affected, just by Copilot's host process being alive.
Suggested fix
- Stop mutating
process.env in the equivalent of bHt.
- If the SDK shells out to
git itself and needs this hardening, pass the GIT_CONFIG_* overrides via the env option of its own spawn/execFile calls, scoped to those children only.
- Alternatively, expose an explicit opt-in (and have callers like the VS Code extension decide whether to use it) rather than applying it unconditionally on import.
Summary
The Copilot CLI's
@github/copilotpackage (v1.0.49, distributed via npm and also bundled with the GitHub Copilot Chat VS Code extension) unconditionally mutates the host process'sprocess.envat SDK initialization to inject a Git hardening setting:Because
process.envis the process-wide environment, this propagates to every child process spawned from that host for its lifetime. When the host is VS Code's extension host (the Copilot Chat extension bundles@github/copilotand loads./sdk), this includes:Any of those that perform Git operations against bare repositories — a legitimate, common pattern (SwiftPM caches, bare clones, server-side mirrors, tooling that creates ephemeral bare repos) — then fail with:
even though the user's own Git configuration says
all(or is unset, which defaults toall). There is no UI for this, no setting to opt out, and from the affected process's point of view the change is invisible —git config --get safe.bareRepositoryin the user's own shell still returnsallbecause the override is only carried throughGIT_CONFIG_*env vars inherited from the SDK host process tree.Where
The package source isn't published in this repo, so the evidence is from the shipped artifact:
<vscode>/Contents/Resources/app/extensions/copilot/node_modules/@github/copilot/sdk/index.js(the same@github/copilot1.0.49 that's on npm), minified function:Invoked from the SDK module's top-level init (
ky = A(() => { ...; bHt(); ... })), so the mutation happens as soon as the SDK is imported.If linkable source exists in an internal repo, please update the report — I could only verify against the minified bundle.
Versions
@github/copilot1.0.49 (also installable standalone vianpm i -g @github/copilot)Repro (standalone, no VS Code required)
Expected (post-mutation):
In VS Code, the same symptom appears in any debuggee/test process the extension host spawns.
git config --show-origin --show-scope --get-all safe.bareRepositoryinside that process reportscommand command line: explicit(i.e. it came from the inheritedGIT_CONFIG_*env triple, not from any config file).Impact
safe.bareRepository=allwhile running under a host that has imported the SDK — most importantly VS Code with Copilot Chat installed, which is the default in modern installs.process.envto injectsafe.bareRepository=explicitfor all spawned processes microsoft/vscode#319210; closing in favor of this issue at the source.Why this is a scope problem
safe.bareRepository=explicitis a personal hardening preference. Git positions it as something a user opts into in their own global config because they personally don't use bare repositories. The SDK silently applying it to the entire host process (and therefore to every child the user spawns from that host) is a global policy change the user did not opt into, cannot opt out of, and cannot even see without inspectingprocess.env. Even users who never call any Git-touching Copilot API are affected, just by Copilot's host process being alive.Suggested fix
process.envin the equivalent ofbHt.gititself and needs this hardening, pass theGIT_CONFIG_*overrides via theenvoption of its ownspawn/execFilecalls, scoped to those children only.