anthropics / anthropics/claude-code

Cloud sessions: GH_TOKEN set in environment variables is ignored for api.github.com; Dependabot alerts unreachable

Offen
#88,198 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
area:docs area:networking area:security bug platform:web
Vorherrschende Sprache
Python
Sterne
145k
Forks
23.1k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

## Summary

In an Anthropic-hosted cloud session, a `GH_TOKEN` / `GITHUB_TOKEN` set in the cloud environment's variables is present in the container but **has no effect on outbound `api.github.com` requests**. The GitHub proxy re-authenticates every REST call with the session's own credential, so `gh` runs as the Claude GitHub App user-to-server identity no matter what token is set.

The docs currently state the opposite, which is what led me down a long debugging path.

Two asks, separable:

1. **Docs correction** (small): make it explicit that a user-supplied token does not authenticate `api.github.com` requests.
2. **Capability gap** (the reason I set a token at all): security alerts are unreachable from cloud sessions. `dependabot/alerts` is rejected by GitHub because the proxy's credential lacks `dependabot_alerts: read`, and no user-supplied credential can substitute.

## Environment

- Claude Code `2.1.237`, Anthropic-hosted cloud environment (Trusted network access)
- `gh` `2.45.0`, installed at `/usr/bin/gh`
- Auth method: Claude GitHub App
- `GH_TOKEN` / `GITHUB_TOKEN` set in the environment's variables to a fine-grained PAT (`github_pat_…`, 93 chars). Not the `proxy-injected` placeholder — the values pass through to the container intact.

## Reproduction

With a fine-grained PAT set in the environment variables, replace it inline with a syntactically invalid value:

```console
$ GH_TOKEN=github_pat_TOTALLY_INVALID_0000 gh api user --jq '{login,type}'
{"login":"christophehurpeau","type":"User"}
```

An invalid token authenticates successfully. Response headers are identical for the real PAT and the garbage value:

```
Github-Authentication-Token-Expiration: 2026-08-20 16:46:12 UTC
X-Oauth-Scopes:
X-Accepted-Github-Permissions: allows_permissionless_access=true
```

Empty `X-Oauth-Scopes` plus a same-day expiry indicate a short-lived GitHub App user-to-server token, not the fine-grained PAT that was set.

A related symptom that makes this confusing to diagnose: `gh auth status` and `gh api` disagree, because the former validates over GraphQL (which the proxy pins to a fixed operation set) while the latter goes through the REST path.

```console
$ gh auth status
github.com
X Failed to log in to github.com using token (GH_TOKEN)
- The token in GH_TOKEN is invalid.

$ gh api user --jq .login
christophehurpeau
```

## Docs discrepancy

[Configure cloud environments § Work with GitHub issues and pull requests](https://code.claude.com/docs/en/cloud-environments) says:

> If you set a token, it passes through to the container unchanged, so your scripts, and GitHub's `gh` CLI if you install it, use it directly.

The first half is accurate — the environment variable arrives unchanged. The second half is not: `gh` does **not** use it against `api.github.com`. The § GitHub proxy section is closer, but scopes the caveat to GraphQL only:

> The restriction applies to every request through the proxy regardless of the credentials you supply, so a `GH_TOKEN` you set gets the same 403.

In practice credential substitution applies to REST as well. Suggested wording: a token you set is usable by scripts that talk to other hosts, but requests to `api.github.com` are re-authenticated by the proxy and a user-supplied token cannot widen (or narrow) what the session can reach.

Minor, same page: it states "GitHub's `gh` CLI isn't pre-installed" and gives setup-script install instructions, but `gh` 2.45.0 is present at `/usr/bin/gh` in this environment.

## Capability gap: security alerts

The three failure modes are distinguishable by the `documentation_url` in the error body, which is useful for triage:

| Layer | Signature | Endpoints observed |
| ------------------------------------ | ---------------------------------------------------- | ---------------------------------------------------------------------- |
| Proxy path allowlist | `documentation_url: docs.anthropic.com/…` | `secret-scanning/alerts`, `vulnerability-alerts`, `user/installations` |
| Proxy GraphQL pin | `This GraphQL query is not enabled for this session` | `gh pr list` and other GraphQL-backed commands |
| GitHub, using the proxy's credential | `documentation_url: docs.github.com/…` | `dependabot/alerts` |

So Dependabot alerts pass the proxy allowlist and are rejected by GitHub itself:

```console
$ gh api "repos/OWNER/REPO/dependabot/alerts?state=open"
{"message":"Resource not accessible by integration",
"documentation_url":"https://docs.github.com/rest/dependabot/alerts#list-dependabot-alerts-for-a-repository",
"status":"403"}
```

Identical response with the garbage token, confirming the user-supplied PAT is not a factor.

`GET /repos/{owner}/{repo}/dependabot/alerts` requires `dependabot_alerts: read` for App tokens, or `security_events` for OAuth/classic tokens ([community discussion #60612](https://github.com/orgs/community/discussions/60612)). The Claude GitHub App credential has neither, and because the proxy owns the `Authorization` header there is no supported way for a user to supply a credential that does.

Net effect: a cloud session cannot answer "what security alerts are open on this repo?" — a natural request for an agent that is otherwise well suited to triaging and fixing dependency advisories. The workaround is to leave the session and run `gh api` locally, or to infer the alert set indirectly from open Renovate/Dependabot PR titles and bodies, which misses any alert without an available fix.

## Requests

1. Correct the `GH_TOKEN` passthrough wording (and the `gh` pre-install note).
2. Add `dependabot_alerts: read` to the Claude GitHub App's requested repository permissions, so alerts are readable when an installation grants it.
3. Consider `secret_scanning_alerts: read` and adding `secret-scanning/alerts` to the proxy path allowlist, for the same reason. Lower priority — secret scanning results are more sensitive, so gating it differently is reasonable.
4. Optional, cheap, and would have saved most of this investigation: have the proxy surface a distinguishable response when it substitutes a credential the caller explicitly supplied, rather than silently succeeding as a different identity.

## Possibly related

- #70474 — user-supplied PAT overridden by the sandbox credential layer in routines (closed, not planned)
- #61189 — proxy OAuth credential lacks `workflow` scope, blocking `.github/workflows/*` writes
- #11078 — proxy strips `Authorization`, breaking GitHub Packages npm auth
- #10108 — egress proxy and GitHub subdomains

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Start with the cloud-environments documentation section and the GitHub proxy behavior described in the reproduction commands. Verify the REST endpoints and response signatures for api.github.com, Dependabot alerts, and secret-scanning alerts. Done means the token and gh wording is accurate and the requested App permissions and proxy allowlist changes have clear, reviewed decisions.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
github
Bereich
api, authentication, cloud, documentation, security
Issue-Typ
Feature
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
48/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.