# Your AI Tools Are the Attack Surface Now

AI coding tools didn't create supply-chain risk. They moved the blast radius into developer and build environments.

*July 2026*

> The old supply-chain question was: can this dependency reach production? The new one is: can this tool reach the machine that can reach everything else?

The [axios compromise](https://github.com/axios/axios/issues/10604) matters here because it landed in developer and build environments that now run agents, not just editors and scripts.

A poisoned package does not need to reach production first if it can reach the workstation with source, shell access, package tokens, cloud CLIs, MCP config, browser sessions, and agent permissions.

In the Axios case, an npm maintainer account was compromised. Malicious axios versions were published. A hidden dependency, [`plain-crypto-js`](https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan), carried a cross-platform remote access trojan. The attack used a postinstall step, which is exactly the kind of thing developers have trained themselves to ignore because most installs are boring.

A short exposure window is still enough time when [half of organizations adopt a new third-party library version within a day of release](https://www.datadoghq.com/state-of-devsecops/).

That is the new attack surface. Not AI in the abstract. The local environment where AI tools act.

## The target moved

Classic supply-chain defense asks whether malicious code can ship to production. That is still the right question. It is no longer the only question.

A compromised dependency used to get a few common chances: run during install, read environment variables, inspect the current project, maybe phone home. Those were serious already. AI coding tools raise the value of the same foothold because the environment now has tools, credentials, and permission paths attached.

The package does not need to own production if it can own the workstation that can later deploy, push, fetch secrets, trigger CI, or hand an agent trusted context. It can look for credentials. It can tamper with generated code. It can poison context that an assistant will later treat as project truth. It can create instructions that look like documentation. It can wait for the human to ask the agent to do the next privileged thing.

That last part matters. Some payloads are not binaries. In agent systems, text can become operational. A malicious MCP tool description, README, issue body, dependency comment, or fixture can become an instruction path if the agent is allowed to treat untrusted text as trusted work context.

## Three failure modes are converging

The first failure mode is old-fashioned package compromise. Axios is the clean example: compromised publishing path, malicious dependency, install-time execution, credential exposure risk, and remote access.

The second failure mode is malicious developer content. [Jamf has documented attacks](https://www.jamf.com/blog/threat-actors-expand-abuse-of-visual-studio-code/) that abuse Visual Studio Code workspace trust and task execution. The repo looks like work. The editor asks whether you trust it. The task runs. That was already a bad pattern before agents started reading repos for intent.

The third failure mode is agent-context compromise. [Research on AI-assisted development tools and MCP clients](https://arxiv.org/abs/2603.21642) has shown that prompt injection can move through tool descriptions and other context channels. Separate [MCP safety work](https://arxiv.org/abs/2504.03767) demonstrates MCP-enabled attacks involving malicious code execution, remote access, and credential theft. A [remote-MCP measurement study](https://arxiv.org/abs/2605.22333) found 7,973 live servers, with 40.55% exposing tools without authentication; every one of 119 testable OAuth-enabled servers had at least one flaw.

1. Code runs during install.
2. The workspace asks the editor to run something.
3. The agent reads malicious instructions and acts on them.

The common target is the developer environment.

## CVE scanners are necessary and late

CVE scanners are useful. They are also designed around a slower kind of truth: a vulnerable component is known, named, assigned, indexed, and then detected.

That does not cover the first hour of a malicious package. It does not cover a maintainer account that just shipped a bad version. It does not cover a prompt injection hidden in a tool description. It does not cover a repo that weaponizes a trusted editor workflow. It does not cover an MCP server that is not "vulnerable" in the traditional sense, but is simply too powerful for the context where it runs.

This is why behavioral controls matter. The question is not only "is this dependency known-bad?" It is also "what did it try to do after it arrived?"

Did install scripts run? Did a package read `.ssh`? Did a tool touch a cloud config? Did an agent call an MCP tool that had never been used in this project before? Did a new outbound host appear during a code-generation run? Did a supposedly local task try to write outside the workspace?

If your defense cannot answer those questions, it is not a gate. It is a report.

## What a real receipt blocks

A receipt is not a pretty log. It is the record that lets you prove what happened and where the run stopped.

For this class of attack, the receipt should make the boring controls visible:

- Install-time payload: package scripts are blocked by default, with a named exception when a project really needs them.
- Credential harvest: reads of `.ssh`, cloud config, keychains, token stores, and `.env` files fail unless the run explicitly owns that scope.
- Prompt-injected action: untrusted text can enter context, but it cannot silently grant tool permission.
- Exfiltration: non-allowlisted outbound hosts are denied or at least surfaced as a human-visible event.
- Quiet persistence: new packages, new scripts, new editor tasks, new MCP servers, and new outbound hosts create a diff.

That is what turns a posture into a practice artifact. The receipt should not say "secure." It should say what was attempted, what was denied, what was allowed, and who accepted the remaining risk.

It can be small:

```yaml
run: dependency-update
scope: workspace
attempted:
  - npm install axios@1.14.1
denied:
  - lifecycle script: postinstall
  - read: ~/.ssh/*
  - read: ~/.config/cloud/*
  - outbound: unapproved-host.example
allowed:
  - registry fetch: registry.npmjs.org
  - mcp tool: filesystem.read ./src
exception:
  - none
verdict: blocked before agent context
```

Here is the kill chain in plain form:

1. A package install tries to run a postinstall step. The package manager blocks scripts by default. If the build needs scripts, the exception is local, named, and reviewed.
2. Code that still executes tries to read credentials. Deny rules block the obvious paths first: SSH keys, cloud credentials, keychains, `.env` files, package tokens.
3. The agent encounters malicious instructions in repo text or tool metadata. The runner treats that text as input, not authority. Tool calls still require policy.
4. Something tries to exfiltrate. Network egress is allowlisted for the job or at least logged as a new destination.
5. The attacker tries to persist quietly. The next receipt shows a new package, task, tool, script, or outbound host.

None of that is exotic. Most of it is unglamorous configuration and a little discipline. That is the uncomfortable part: the gap between "defenses exist" and "defenses are deployed" is usually not research. It is an afternoon nobody has budgeted.

## The practical minimum

Start with the controls that block the common paths.

Two minutes:

- Turn on `ignore-scripts=true` for npm by default where your projects can tolerate it.
- Remove MCP servers you do not actively use.
- Stop opening unknown repos in trusted editor mode.
- Stop running agents in all-access mode against unfamiliar code.

For npm, the blunt version for a dev account is:

```sh
npm config set ignore-scripts true
```

For a single repo, put `ignore-scripts=true` in that project's `.npmrc`.

Ten minutes:

- Put credential paths on a deny list: `.ssh`, cloud config, keychains, token stores, `.env` files.
- Make new outbound hosts visible during agent runs.
- Require a package-age or review delay for routine dependency updates.
- Keep a per-project exception file for install scripts instead of letting every package decide.

One afternoon:

- Run agents in a workspace-scoped sandbox by default.
- Treat every MCP server like a production integration to your machine.
- Record package changes, tool calls, outbound connections, denied reads, and human approvals in one receipt.
- Make the receipt something another person can inspect without replaying chat scrollback.

The more useful the tool becomes, the less acceptable ambient authority gets.

## The floor

The future version is stronger: sandboxed MCP runtimes, safer package distribution, agent tools designed to fail closed, and receipts that travel with the work.

The floor is simple: no silent scripts, no ambient credential reads, no unreviewed tool authority, and no success claim without a receipt.
