Resources | Blog

June 9, 2026

Claude Code's MCP Traffic Can Be Silently Hijacked to Steal OAuth Tokens

Harshavardhan Reddy

Table of contents

Executive summary

A supply chain attack targeting Claude Code's local configuration file can silently redirect MCP traffic to an attacker-controlled proxy, intercepting OAuth bearer tokens for Jira, Confluence, GitHub, and other connected platforms before they reach their intended destination. The tokens are persistent, broadly scoped, and stored in plaintext. When used by the attacker, they originate from Anthropic's egress IP range, making every request appear legitimate to provider-side audit logs. This is not a bug in the traditional sense. It is an identity architecture problem. MCP has become an OAuth delegation layer, and the credentials it accumulates are ungoverned, absent from IAM inventories, not subject to access reviews, and carrying full grant-time permissions with no scope enforcement after the initial authorization.

A configuration file with no boundaries

When a developer connects Claude Code to a SaaS platform through an MCP integration, an OAuth bearer token is stored in a local configuration file at ~/.claude.json. That file also controls which project directories Claude Code trusts and which endpoints it sends credentials to. There is no separation between credential storage and routing configuration. They live in the same plaintext file with identical permissions and no integrity enforcement. That architecture is the entire attack surface.

A supply chain compromise does not need to exploit the provider, bypass authentication, or escalate privileges. It only needs to reach that file and rewrite the endpoint URL to which the token is sent. The token is then delivered to an attacker-controlled proxy on every subsequent OAuth flow, automatically, without the developer ever seeing anything unusual. The risk scales directly with adoption. Every developer who connects a Claude Code MCP integration adds a persistent, broadly scoped credential to a file that most security teams are not monitoring.

How the attack moves from install to credential theft

Delivery 
The attack enters through a malicious npm package designed to survive casual inspection. A postinstall hook fires silently at install time, with no prompt, no warning, and no visible output. By the time the developer's terminal shows a successful install, the configuration has already been modified.

Path Seeding 
The hook's first move is to edit ~/.claude.json and pre-populate common developer project directories as trusted. Claude Code uses this trust list to determine whether to prompt the user when opening a folder. With the paths already seeded, no prompt ever fires. The attacker has pre-authorized themselves across the developer's entire project workspace without a single approval click.

Endpoint Rewrite 
A sessionStart hook is inserted into the configuration. Every time Claude Code opens a trusted project, that hook rewrites the mcpServers URLs, the addresses Claude Code uses to reach Atlassian, GitHub, and other connected platforms, replacing them with a localhost proxy the attacker controls. Claude Code sees a URL and connects to it. There is no validation that the URL matches what the user originally configured.

Token Interception 
When the developer connects or reconnects an MCP integration, Claude Code runs a full OAuth flow against the rewritten URL. The bearer token, which grants full access to that user's Jira, Confluence, or GitHub account, passes through the attacker's proxy before reaching the real service. The proxy forwards the request normally, the integration appears to work, and the developer sees nothing unusual. The attacker now holds a valid, active credential scoped to everything the user authorized at the time of grant.

Persistent Reseeding 
The hook fires on every load of a Claude Code session, not just once. This is what makes the standard incident response reflex dangerous here. Rotating the OAuth token, the first action most teams take when a credential is suspected of being compromised, actively refeeds the attacker. The hook rewrites the configuration before the next refresh, and the new token is delivered straight to the proxy. The attacker receives a fresh credential without doing anything.

What makes these tokens an exceptional target

Not all credentials are equal. OAuth bearer tokens stored by Claude Code sit at the intersection of four properties that make them exceptionally valuable. They are persistent. A single interception is enough. Claude Code stores the token alongside a refresh token in ~/.claude.json, so the credential persists across session restarts and renews automatically. The attacker does not need repeated access to the machine. They are broadly scoped. The token inherits every permission the user granted at authorization time, with no narrowing per call and no re-consent required for subsequent operations. Intercepting a token for a Jira integration does not grant read-only access to a single project. It grants whatever the user is authorized for across every resource covered by the grant.

They are stored in plaintext. Bearer tokens, refresh tokens, and the trust flags governing where those tokens are sent all live in the same file with no credential isolation. Compromising the routing configuration and compromising the credentials are the same operation. They are unattributable server-side. When the attacker uses the token, it originates from Anthropic's egress IP range. Every field in the provider's audit log looks legitimate: a valid username, an active session, and a trusted origin. There is no anomaly to detect on the provider side. The only evidence of the attack exists in ~/.claude.json on the developer's local machine.

The remediation step that hands the attacker a fresh token

The instinct when a credential is compromised is to rotate it. That instinct is correct in most scenarios. Here it makes things worse. Because the sessionStart hook rewrites the configuration before each OAuth refresh, rotation does not sever the attacker's access. It renews it. The moment Claude Code starts after a token rotation, the hook fires, rewrites the mcpServers URLs to the attacker's proxy, and the next OAuth refresh automatically delivers a fresh credential.

The correct remediation sequence is the opposite of what most teams do by reflex. Remove the hook first. Audit and correct every URL in the mcpServers block of ~/.claude.json. Rotate the credential only after both of those steps are complete and verified. Doing it in the wrong order turns the recovery process into the delivery mechanism.

The attack that leaves no trace

Security teams reviewing provider-side audit logs will find nothing anomalous. The requests originate from Anthropic's egress range. The session is authenticated. The scopes match the grant. The username is correct. This is the core of the problem. The attacker is not impersonating the user. They are the user, as far as every downstream system is concerned. The token is real. The session is real. The permissions are real. Traditional detection controls, perimeter alerts, authentication failures, and lateral movement signatures have nothing to fire on. The attack lives entirely inside a legitimate identity. And unless someone is monitoring ~/.claude.json for URL changes in the mcpServers block, it is invisible.

What to investigate right now

Security teams should treat the following as immediate investigative priorities for any environment running Claude Code with MCP integrations:

  • Verify every URL listed under mcpServers in ~/.claude.json on developer machines. Any localhost proxy address warrants immediate investigation.
  • Audit installed npm packages for postinstall lifecycle hooks that touch ~/.claude.json or the developer's home directories.
  • Review SaaS provider audit logs for requests from Anthropic egress IPs that do not correspond to expected developer activity.
  • Confirm the sessionStart hook section of ~/.claude.json is absent or contains only the expected configuration before rotating any connected OAuth tokens.

The Identity Architecture Problem Underneath the Attack

This attack works not because of a bug, but because the identity architecture around MCP lacks controls. ~/.claude.json contains credential material, trust configuration, and routing configuration in a single plaintext file, with no integrity enforcement, signing, or validation against an expected state. A hook can rewrite where the token is sent and reassert that rewrite on every session load because nothing in the current design separates credential storage from endpoint configuration.

MCP integrations have quietly become an OAuth delegation layer. Tokens for Jira, Confluence, GitHub, and other platforms are accumulating in a local file outside any IAM inventory, not subject to access reviews, and carry full grant-time permissions with a refresh token that keeps them alive across session restarts. The assumption underneath all of it is that the developer's machine is trusted. That assumption is the entire attack surface.

How Unosecur closes the gap

The attack succeeds because the credential is ungoverned from the moment it is issued, and every system downstream treats it as legitimate. The right intervention is at the identity layer, before the credential accumulates and before the scope is inherited from whatever the user approved at grant time. The MCP Auth Gateway brokers the OAuth flow and enforces per-agent scope at authorization. Each integration gets only the permissions it actually needs, defined explicitly. When an attacker rewrites the endpoint URL and intercepts the token, they get a scoped-down credential, not a full grant. The interception can still happen. The payoff shrinks considerably.

The gateway also enforces Just-in-Time access. One of the properties that makes this attack durable is that the token persists indefinitely, surviving session restarts and renewing itself through a refresh token. JIT removes that property. Access to MCP integrations can be granted for exactly the window it is needed, and when that window closes, the credential is automatically revoked. An attacker who intercepts a token that no longer exists has nothing to use. MCP-delegated tokens never appear in an IAM dashboard, an access review, or any credential inventory. That is the structural gap this attack relies on. NHI and AI agent discovery brings these credentials into the Unified Identity Fabric as governed identities alongside every human identity, service account, and AI agent already under management. The AI Agent Dashboard gives each agent its own risk lens: permissions it holds, data sources it can reach, the execution path it uses to get there, and the findings attached to it. When a token carries access beyond its stated purpose, it surfaces here.

Every request in this attack looks clean to the provider. Valid session, correct scopes, trusted origin. Because no single provider has the full picture, each one sees a legitimate request and flags nothing. Unosecur builds a behavioral baseline for each identity across all connected systems, so when a token starts being used outside that baseline, the anomaly becomes visible even when every individual log looks clean. Agent trigger logs are auditable. When something is wrong, there is a trail. The plaintext file, the malicious package, and the postinstall hook live on the developer machine. Endpoint hygiene is still necessary, and the detection steps above apply. What Unosecur changes is what a stolen token is worth, whether it was in any inventory to begin with, and whether your team has a signal when every provider log stays silent.

The bottom line

The vulnerability here is not in Claude Code. It is in the assumption that a local configuration file is an acceptable place to co-locate credential material, trust controls, and routing configuration with no integrity enforcement and no governance layer above it. MCP has introduced a new class of non-human identity risk that most organizations are not yet inventorying. These tokens do not appear in IAM dashboards. They are not reviewed. They carry broad permissions and renew themselves automatically. And when they are compromised, standard incident response makes the situation worse rather than better.

The developer machine is not the trust boundary it was once assumed to be. Treating MCP-delegated credentials as governed identities rather than invisible configuration is not a future best practice. It is a present requirement.

Ready To Secure Your Identities?