Cursor in agents window can't access github via gh while it can in the repo window

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Cursor IDE foreground agent — Shell tool blocks api.github.com and the documented required_permissions: ["all"] escape hatch is not reachable

Summary

In a foreground (in-IDE) Cursor agent session, the Shell tool runs every
command inside a network-allowlist sandbox that blocks outbound HTTPS to
api.github.com (synthetic 403 returned with Content-Type: text/plain).
The sandbox footer printed under every Shell result tells the agent it can
escape the sandbox by passing required_permissions: ["all"]:

SANDBOXING: This command ran in a sandbox with the following restrictions:

  • Filesystem: Write access limited to the workspace directory, read access to the rest of the filesystem
  • Network access: Limited (allowlist only)
    If you think the command failed due to sandbox restrictions, re-run with the required_permissions that you need (such as [“full_network”]) or use required_permissions: [“all”] to run outside the sandbox entirely. Don’t needlessly ask for permission.

But the foreground agent’s Shell tool JSON Schema does not declare
required_permissions as a parameter. The harness validates against the
declared schema, so any attempt to include the field is silently stripped
before reaching the runtime, and every retry stays sandboxed.

This produces a confusing failure mode where:

  1. gh auth status reports “The token in keyring is invalid” (because
    gh makes a GET /user call to verify the token, the sandbox returns
    a 403, and gh interprets that as auth rejection).
  2. The agent reasonably concludes the user’s gh token is dead and asks
    them to re-authenticate.
  3. The user (correctly) demonstrates gh works fine in their own terminal.
  4. Both the agent and the user lose ~30 minutes diagnosing a fictional
    “keyring ACL” problem before realizing the failure is sandbox network
    policy, not auth.

The most striking part: other agents in the same Cursor app, same
machine, same user, same token, work without issue.
Background/Cloud
Agents have their own VM with its own allowlist. The “repo agents” or
Composer agents the user works with elsewhere apparently get a Shell tool
schema that does declare required_permissions (because they routinely
run gh pr edit, gh api, etc. against private repos without trouble).
The foreground agent that I am does not.

Environment

Field Value
Cursor app version 3.6.31 (build 3.6.31)
macOS 26.5 (build 25F71)
Architecture arm64
gh version 2.83.1 (2025-11-13)
gh auth Valid, stored in macOS Keychain via gh:github.com keyring entry
Agent model Claude Opus 4.7 (foreground / in-IDE agent, “Agent” mode)

Repro

This happened in a real working session over several hours. Easy to
reproduce in any foreground Cursor agent session:

  1. Open a workspace in a private GitHub repo.

  2. Confirm gh auth status works in your terminal (it does):

    $ gh auth status
    github.com
      ✓ Logged in to github.com account <user> (keyring)
      - Active account: true
      - Git operations protocol: https
      - Token: gho_***
      - Token scopes: 'gist', 'read:org', 'repo', 'workflow'
    
  3. Ask the agent to do anything that requires the GitHub API (e.g.
    “open a PR for this branch” or “post a comment on PR #N”).

  4. Watch the agent attempt gh pr create / gh pr comment / gh api,
    then see:

    X Failed to log in to github.com account <user> (keyring)
      - The token in keyring is invalid.
    

    or:

    Post "https://api.github.com/graphql": Forbidden
    
  5. Direct verification that the issue is sandbox, not auth:

    $ curl -sI -H "Authorization: token $(security find-generic-password \
        -s 'gh:github.com' -a '<user>' -w \
      | sed 's/go-keyring-base64://' | base64 -d)" \
      https://api.github.com/user
    HTTP/1.1 403 Forbidden
    content-type: text/plain
    content-length: 92
    

    GitHub’s real auth-rejection responses are JSON ({"message": "Bad credentials", ...}). A plaintext 403 with content-length: 92 is the
    sandbox interceptor. The same curl in the user’s own terminal
    succeeds with a 200 + JSON body.

  6. The agent attempts to follow the sandbox footer’s instructions and
    pass required_permissions: ["all"] to the Shell tool, but the
    field is not declared in the agent’s visible Shell schema and gets
    stripped by harness validation. Every retry remains sandboxed.

Expected behavior

One of the following:

  • (Preferred) The foreground agent’s Shell tool schema declares
    required_permissions so the documented escape hatch actually works.
    Then gh / curl / any HTTPS call to api.github.com succeeds with
    the user’s existing credentials.
  • (Alternative) api.github.com is added to the default network
    allowlist so foreground agents can use gh against private repos
    without escalation. (Background Agents and Composer / repo agents
    apparently already have this — parity would be the cheapest fix.)
  • (Alternative) The sandbox footer text is updated to NOT advertise
    required_permissions: ["all"] to agents that don’t actually have
    access to that parameter, so the agent doesn’t waste cycles
    attempting an impossible workaround and the user doesn’t get told
    three different incorrect diagnoses before the agent realizes the
    doc is lying to it.

Actual behavior

The sandbox footer advertises an escape hatch the foreground agent
cannot reach, gh API calls fail with a misleading “invalid token”
error, the agent over-confidently mis-diagnoses the failure as a
keyring/ACL/auth-token-rotation problem, and the user has to either
manually copy-paste content into the GitHub web UI or spin up a
separate agent session to do the GitHub work.

Workarounds in use today

  1. Hand the GitHub task to a separate “repo agent” session that has
    the right Shell schema. Works, but adds cross-session coordination
    overhead — the parent agent has to write a self-contained prompt
    with all required context (PR number, file paths, full comment
    bodies, etc.) because the new agent can’t see the parent’s
    conversation. We’ve been doing this for ~10 GitHub operations on a
    single Jira ticket over the past week. It works but turns ~30
    second gh pr comment calls into ~5 minute prompt-handoff cycles.
  2. cursor-ide-browser MCP for UI-shaped actions (edit PR
    description, post comment by clicking through the page). Works but
    slower per action; useful as fallback.
  3. User runs the gh command themselves from their terminal.
    Works, but defeats the point of having an agent.

Impact

For workflows that touch GitHub at all — reviewing PR comments,
editing PR descriptions, opening companion PRs across repos, posting
review replies, checking CI status, updating labels — the foreground
agent is effectively useless and has to delegate every step.

Suggested fix priority

If only one thing can change: expose required_permissions in the
foreground agent’s Shell schema
, OR remove that field from the
sandbox footer documentation if it’s never going to be available.
Either eliminates the confusion loop. Best fix: do both, plus
allowlist api.github.com by default — gh is the canonical way
agents interact with GitHub and the current behavior makes that path
unusable.

Steps to Reproduce

Ask the foreground agent to run each of these via its Shell tool, one
at a time, in the open workspace. Substitute any private repo you have
read access to for <org>/<private-repo>.

Step 1 — gh REST endpoint, hits api.github.com:

gh api repos/<org>/<private-repo>

Expected (in a real terminal): JSON body describing the repo.
Actual (inside the foreground agent’s Shell):

Get "https://api.github.com/repos/<org>/<private-repo>": Forbidden

Step 2 — gh GraphQL endpoint, also hits api.github.com:

gh repo view <org>/<private-repo> --json url,description

Actual:

Post "https://api.github.com/graphql": Forbidden

Step 3 — raw curl to api.github.com with a known-good token,
bypassing gh entirely:

TOK=$(security find-generic-password -s 'gh:github.com' -a '<user>' -w \
  | sed 's/go-keyring-base64://' | base64 -d)
curl -sI -H "Authorization: token $TOK" \
     -H "Accept: application/vnd.github+json" \
     https://api.github.com/repos/<org>/<private-repo>

Actual:

HTTP/1.1 403 Forbidden
content-type: text/plain
content-length: 92

This is the sandbox interceptor, not GitHub. Real GitHub
auth-rejection responses are Content-Type: application/json with a
{"message": "Bad credentials", ...} body. A plaintext 403 with
content-length: 92 and no X-GitHub-Request-Id header is the
sandbox synthesizing the response before the request leaves the host.

Step 4 — same private repo, but via github.com (git protocol) instead
of api.github.com:

git ls-remote --heads https://github.com/<org>/<private-repo>.git develop

Actual:

3c5e26243731528223652cc7cc72c7d4dc8ed4dd	refs/heads/develop
exit=0

Works. Same host family, same auth, different subdomain.

Step 5 — read an arbitrary file from that same private repo, again
via git protocol:

cd <any-existing-git-repo-in-workspace>
git fetch https://github.com/<org>/<private-repo>.git develop --depth 1
git show FETCH_HEAD:<path/to/any/file>

Actual: file contents printed to stdout. Works.

Expected Behavior

cursor ide in agents view can execute the same gh commands as cursor in the repo view.
Worth mentioning that I need to be connected to a VPN to access github. I am connected all the time but seems like there are different permissions for network in the agents view vs the repo window.

Screenshots / Screen Recordings

Operating System

MacOS

Version Information

Version: 3.6.31 (Universal)
VS Code Extension API: 1.105.1
Commit: 81fcf2931d7687b4ff3f3017858d0c6dee7e2a60
Date: 2026-05-31T17:46:29.630Z
Layout: glass
Build Type: Stable
Release Track: Default
Electron: 39.8.1
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
xterm.js: 6.1.0-beta.220
OS: Darwin arm64 25.5.0

Additional Information

I use a vpn to connect to github

Does this stop you from using Cursor

No - Cursor works, but with this issue

The “token in keyring is invalid” error is a red herring. gh reports that when its outbound API request is blocked, not because there’s actually a problem with your credentials.

The sandbox has a default network allowlist that includes github.com (which is why git operations work fine), but it doesn’t include api.github.com. Since gh CLI makes all its REST and GraphQL calls through api.github.com, those get blocked, and gh misinterprets the resulting 403 as an auth failure.

To fix this, create a .cursor/sandbox.json file in your project root:

{
"networkPolicy": {
"default": "deny",
"allow": [
"api.github.com"
]
}
}

You can also place this in ~/.cursor/sandbox.json to apply it across all workspaces.

Then check your Auto-Run Network Access setting in Cursor Settings > Agents > Auto Run. Make sure it’s set to sandbox.json + Defaults or Allow All so the merged allowlist is active.

Full reference for sandbox configuration: sandbox.json reference

You may also find this related thread helpful, where a similar question about gh in the sandbox was discussed in more detail: Auto-Run network access sandbox.json + Defaults seems to not be working

Regarding the asymmetry between the agents window and the repo window - this is something we’ve seen before with the newer Glass UI. The agents window enforces sandbox restrictions differently than the editor-embedded Composer, and that gap is on our team’s radar.

Let me know if adding api.github.com to your sandbox.json resolves the issue!

yes this solution worked. Thank you for the explanation and fast response