Skip to content

fix: always derive GH_HOST from GITHUB_SERVER_URL to prevent proxy leakage#1493

Merged
lpcox merged 6 commits intomainfrom
copilot/fix-gh-host-proxy-passthrough
Mar 29, 2026
Merged

fix: always derive GH_HOST from GITHUB_SERVER_URL to prevent proxy leakage#1493
lpcox merged 6 commits intomainfrom
copilot/fix-gh-host-proxy-passthrough

Conversation

@lpcox
Copy link
Copy Markdown
Collaborator

@lpcox lpcox commented Mar 29, 2026

Problem

When --env-all passes through a proxy-rewritten GH_HOST (e.g. localhost:18443 from a DIFC proxy), the gh CLI inside the container fails:

none of the git remotes configured for this repository correspond to the GH_HOST environment variable

The old code had a !environment.GH_HOST guard that preserved whatever value --env-all passed through, even if it was a proxy artifact.

Fix

Always derive GH_HOST from GITHUB_SERVER_URL (the canonical source injected by the Actions runner), overriding any proxy-leaked values:

  • GHES/GHEC: Sets GH_HOST to the correct hostname derived from GITHUB_SERVER_URL
  • github.com: Deletes any leaked GH_HOST so gh CLI uses its default

GITHUB_SERVER_URL is set by the runner itself and always points to the real GitHub instance — it is never rewritten by proxies.

Tests

  • Updated existing test: now verifies proxy-rewritten GH_HOST is overridden (not preserved)
  • Added new test: verifies proxy-rewritten GH_HOST is removed on github.com

References

…akage

When --env-all passes through a proxy-rewritten GH_HOST (e.g.
localhost:18443 from DIFC proxy), gh CLI fails with "none of the
git remotes correspond to GH_HOST". Fix by always deriving GH_HOST
from GITHUB_SERVER_URL (the canonical source injected by the
Actions runner) instead of preserving leaked proxy values.

For GHES/GHEC: overrides any leaked value with the correct hostname.
For github.com: deletes any leaked GH_HOST so gh CLI uses its
default.

Closes #1492

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@lpcox lpcox requested a review from Mossaka as a code owner March 29, 2026 15:28
Copilot AI review requested due to automatic review settings March 29, 2026 15:28
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 29, 2026

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 82.71% 82.83% 📈 +0.12%
Statements 82.37% 82.49% 📈 +0.12%
Functions 81.22% 81.22% ➡️ +0.00%
Branches 76.03% 76.08% 📈 +0.05%
📁 Per-file Coverage Changes (1 files)
File Lines (Before → After) Statements (Before → After)
src/docker-manager.ts 86.0% → 86.5% (+0.48%) 85.5% → 86.0% (+0.47%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR prevents proxy-leaked GH_HOST values (passed through via --env-all) from breaking gh CLI operations inside the agent container by ensuring GH_HOST is derived from the canonical GITHUB_SERVER_URL.

Changes:

  • Always set GH_HOST from GITHUB_SERVER_URL when targeting GHES/GHEC; otherwise remove any leaked GH_HOST (github.com/unset cases).
  • Update and extend tests to assert proxy-rewritten GH_HOST is overridden/removed as appropriate.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/docker-manager.ts Force GH_HOST to be derived from GITHUB_SERVER_URL, and delete leaked values on github.com/unset paths.
src/docker-manager.test.ts Updates existing test expectation and adds a github.com case to ensure leaked GH_HOST is removed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +639 to +640
// GITHUB_SERVER_URL is injected by the Actions runner and always points to the real
// GitHub instance, so it is the canonical source of truth.
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

The comment says GITHUB_SERVER_URL “always points to the real GitHub instance”, but this function is also used outside GitHub Actions where GITHUB_SERVER_URL can be unset (and the code below explicitly handles that). Consider rewording to clarify this guarantee only applies when the Actions runner injects GITHUB_SERVER_URL (i.e. in GitHub Actions).

Suggested change
// GITHUB_SERVER_URL is injected by the Actions runner and always points to the real
// GitHub instance, so it is the canonical source of truth.
// When running inside GitHub Actions, GITHUB_SERVER_URL is injected by the Actions
// runner and points to the real GitHub instance for the workflow run, so within that
// context it is the canonical source of truth. Outside Actions it may be unset.

Copilot uses AI. Check for mistakes.
Comment on lines +647 to +651
// On github.com (or when GITHUB_SERVER_URL is unset), GH_HOST should not be set.
// If --env-all passed through a proxy-rewritten value, remove it so gh CLI
// uses its default (github.com). See: gh-aw-firewall#1492
delete environment.GH_HOST;
logger.debug('Removed proxy-rewritten GH_HOST (GITHUB_SERVER_URL targets github.com)');
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

The debug message “Removed proxy-rewritten GH_HOST (GITHUB_SERVER_URL targets github.com)” can be misleading because this branch also runs when GITHUB_SERVER_URL is unset/empty/invalid (since extractGhHostFromServerUrl returns null in those cases). Consider adjusting the log message (and/or condition) so it accurately reflects why GH_HOST was removed.

Suggested change
// On github.com (or when GITHUB_SERVER_URL is unset), GH_HOST should not be set.
// If --env-all passed through a proxy-rewritten value, remove it so gh CLI
// uses its default (github.com). See: gh-aw-firewall#1492
delete environment.GH_HOST;
logger.debug('Removed proxy-rewritten GH_HOST (GITHUB_SERVER_URL targets github.com)');
// When GITHUB_SERVER_URL does not yield a custom host (e.g. github.com, unset, or invalid),
// GH_HOST should not be set. If --env-all passed through a proxy-rewritten value, remove it
// so gh CLI uses its default behavior (github.com). See: gh-aw-firewall#1492
delete environment.GH_HOST;
logger.debug('Removed GH_HOST from environment; falling back to gh CLI default since GITHUB_SERVER_URL did not yield a custom host override');

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — Copilot Engine

Test Status
GitHub MCP (last 2 merged PRs) #1486 feat(api-proxy): add WebSocket upgrade support, #1484 [WIP] Fix failing GitHub Actions workflow agent
Playwright (github.com title contains "GitHub")
File write /tmp/gh-aw/agent/smoke-test-copilot-23712406260.txt
Bash verify (cat file)

Overall: PASS

Author: @lpcox | No assignees

📰 BREAKING: Report filed by Smoke Copilot for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — PASS

✅ GitHub MCP: #1486 feat(api-proxy): add WebSocket upgrade support to fix Codex /v1/responses streaming; #1404 chore(deps): bump the all-github-actions group with 21 updates
✅ Playwright: github.com title contains "GitHub"
✅ File write: /tmp/gh-aw/agent/smoke-test-claude-23712406253.txt created and verified
✅ Bash: file contents confirmed

💥 [THE END] — Illustrated by Smoke Claude for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3
Node.js v24.14.0 v20.20.1
Go go1.22.12 go1.22.12

Result: FAILED — Python and Node.js versions differ between host and chroot environments. This is expected behavior: chroot uses the system-installed versions from the Ubuntu base image, while the host runner has newer tool-cache versions.

Tested by Smoke Chroot for issue #1493

@github-actions

This comment has been minimized.

…violation in Codex workflows (#1494)

* Initial plan

* fix: replace xpia.md with safe inline policy to fix cyber_policy_violation

* fix: address code review feedback on xpia.md replacement logic

Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/ecbda070-c667-4859-8ca2-8b15dee1e0a2

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Smoke test results (run 23713266323)

✅ GitHub MCP — #1494: fix: replace xpia.md with safe inline policy | #1486: feat(api-proxy): add WebSocket upgrade support
✅ Playwright — github.com title contains "GitHub"
✅ File write — /tmp/gh-aw/agent/smoke-test-claude-23713266323.txt created and verified
✅ Bash — file contents confirmed

Overall: PASS

💥 [THE END] — Illustrated by Smoke Claude for issue #1493

@github-actions

This comment has been minimized.

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — Copilot Engine

Test Result
GitHub MCP (last 2 merged PRs) #1494: fix: replace xpia.md…, #1486: feat(api-proxy): WebSocket upgrade
Playwright (github.com title) ✅ "GitHub · Change is constant…"
File write /tmp/gh-aw/agent/smoke-test-copilot-23713266304.txt
Bash file verification

Overall: PASS

PR author: @lpcox

📰 BREAKING: Report filed by Smoke Copilot for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3
Node.js v24.14.0 v20.20.1
Go go1.22.12 go1.22.12

Overall: Not all tests passed. Python and Node.js versions differ between host and chroot.

Tested by Smoke Chroot for issue #1493

Replace cybersecurity-triggering content (was using <security> tag,
'network access controls', 'circumventing', 'authentication tokens',
'sandboxed environment') with neutral operational policy language using
a <policy> tag. These terms triggered OpenAI's cyber_policy_violation
filter, causing Smoke Codex to fail with 'temporarily limited for
potentially suspicious activity related to cybersecurity'.

Also add xpiaSafeBlockRegex so the postprocess script is idempotent
when SAFE_XPIA_CONTENT changes (can update already-replaced blocks
without requiring a full recompile from .md source).

Regenerated smoke-codex.lock.yml and secret-digger-codex.lock.yml.

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — PASS

💥 [THE END] — Illustrated by Smoke Claude for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results

GitHub MCP: Last 2 merged PRs retrieved

Playwright: https://github.com title contains "GitHub"
File Write: /tmp/gh-aw/agent/smoke-test-copilot-23713730329.txt created and verified
Bash: File read back successfully

Overall: PASS | PR by @lpcox

📰 BREAKING: Report filed by Smoke Copilot for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3 ❌ No
Node.js v24.14.0 v20.20.1 ❌ No
Go go1.22.12 go1.22.12 ✅ Yes

Result: FAILED — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot for issue #1493

@github-actions

This comment has been minimized.

@lpcox
Copy link
Copy Markdown
Collaborator Author

lpcox commented Mar 29, 2026

@copilot create a fix for this comment #1493 (comment)

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 29, 2026

@copilot create a fix for this comment #1493 (comment)

Fixed in a4dffe1. Both the comment and the debug log message have been updated:

  • The comment at lines 639–641 now clarifies that GITHUB_SERVER_URL is only guaranteed canonical when inside GitHub Actions; outside Actions it may be unset.
  • The debug message now reads 'Removed GH_HOST from environment; falling back to gh CLI default since GITHUB_SERVER_URL did not yield a custom host override', accurately covering all null-host cases (github.com, unset, or invalid GITHUB_SERVER_URL).

@github-actions

This comment has been minimized.

Run npm audit fix to resolve:
- handlebars 4.0.0-4.7.8: critical (JS injection, prototype pollution)
- brace-expansion 4.0.0-5.0.4: moderate (DoS via zero-step sequence)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results

Test Status
GitHub MCP (#1495, #1494)
Playwright (github.com title)
File write
Bash verify

Overall: PASS

💥 [THE END] — Illustrated by Smoke Claude for issue #1493

@github-actions

This comment has been minimized.

@github-actions
Copy link
Copy Markdown
Contributor

🤖 Smoke test results for @lpcox's PR:

✅ GitHub MCP — Last 2 merged PRs: #1495 "fix: use neutral policy language in SAFE_XPIA_CONTENT..." · #1494 "fix: replace xpia.md with safe inline policy..."
✅ Playwright — github.com title contains "GitHub"
✅ File write — /tmp/gh-aw/agent/smoke-test-copilot-23716653927.txt created and verified
✅ Bash — file read back successfully

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3 ❌ NO
Node.js v24.14.0 v20.20.1 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Result: ❌ Not all tests passed — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot for issue #1493

Remove existsSync guard before readFileSync to eliminate TOCTOU
race condition (js/file-system-race). Use try/catch on readFileSync
instead, which atomically handles missing files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — Copilot ✅ PASS

Test Result
GitHub MCP (last 2 merged PRs) #1495 fix: use neutral policy language... · #1494 fix: replace xpia.md...
Playwright (github.com title) ✅ "GitHub · Change is constant..."
File write + read /tmp/gh-aw/agent/smoke-test-copilot-23716773060.txt
Bash verification

PR author: @lpcox · No assignees.

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — PASS

💥 [THE END] — Illustrated by Smoke Claude for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3
Node.js v24.14.0 v20.20.1
Go go1.22.12 go1.22.12

Result: Not all tests passed. Python and Node.js versions differ between host and chroot environments. Go versions match.

Tested by Smoke Chroot for issue #1493

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color 1/1 passed ✅ PASS
Go env 1/1 passed ✅ PASS
Go uuid 1/1 passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx All passed ✅ PASS
Node.js execa All passed ✅ PASS
Node.js p-limit All passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Generated by Build Test Suite for issue #1493 ·

@lpcox lpcox merged commit 1110a9a into main Mar 29, 2026
61 of 63 checks passed
@lpcox lpcox deleted the copilot/fix-gh-host-proxy-passthrough branch March 29, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GH_HOST passthrough from proxy environment breaks gh pr checkout inside container

4 participants