Black Shard

Insights9 June 2026

AI coding agent security starts with what it can already reach

A coding agent runs with the credential set of whoever launched it, and it takes instructions from whatever it reads, so a dependency README, a ticket comment and a tool description are all places an instruction can be planted. What an agent holds, how injected instructions reach it, and which boundaries genuinely bound it.

A ring of brass keys hanging from a hook beside a heavy steel door latch, lit cold cyan on dark slate

What does an AI coding agent actually hold when it runs?

Most writing about AI coding agent security risks is about the code the agent produces, a missing authorisation check or an invented dependency name an attacker had already registered. The risk that arrives with an agent rather than a chat window is that the agent acts: it reads files, runs shell commands, calls network services and edits your repository, carrying whatever authority the session it was launched from already had. That is a confused deputy, a component holding more privilege than the party instructing it and no reliable way to tell which instructions deserve it.

The inventory is worth writing down, because most teams have never done it. A developer session typically carries a cloud command line token cache under the home directory, a git credential helper that hands a token to anything asking in the right format, private SSH keys, registry tokens in the package manager's config, a cluster config pointing at a service account, browser cookies for every console the developer stays signed in to, and environment files holding connection strings that point somewhere real. An agent with shell access and a readable home directory holds every one of them, and none of it had to be granted, because it was already present and already valid.

That authority has no relationship to the size of the task, which might be to fix one failing test. It is the union of everything the developer can reach without re-authenticating, which in most organisations includes at least one production system and often the ability to publish software customers install. The agent also runs as that person, so its actions land in the cloud sign-in log, the source control audit trail and the database session under a human identity, and after an incident the person has to account for all of them.

How prompt injection reaches a coding agent

An operator types a sentence or two, and everything else the model reads arrives from somewhere else: the files it opened, the README of a dependency it inspected, the ticket it was pointed at, a web page it fetched to check an API signature, a comment on a pull request, and the description text of every tool available to it. The operator's words are a small minority of the tokens in the context window, and every other source is a place an instruction can be planted by someone who never touches your session.

All of it arrives as one stream of tokens, and a token carries no privilege marker. Nothing in the representation records which sentence came from the person paying for the session and which came from a file pulled off the internet, and instruction following is a behaviour learned over text, so text shaped like an instruction tends to be treated as one regardless of origin. Filtering helps and does not give you a boundary, because the adversary writes natural language and can iterate offline against the same filter until something passes.

A useful triage question for any agent configuration is whether three conditions hold at once. The agent can reach data worth taking, it processes content someone outside your organisation can influence, and it has a way to send data outward. Any two is usually survivable, and all three means an injection anywhere in the content it reads can become exfiltration. The work is to break one of the three rather than to write a stronger instruction telling the model to ignore hostile text.

Many agents also read a project instruction file at the start of every session, and many can write files in the repository they are working in. An injection that lands once and writes itself into that file persists, gets committed, and is read by every other developer's agent on the next pull. Treat those files as code running with high privilege, and treat a diff touching one without a stated reason as a finding.

What does connecting an MCP server actually grant?

The Model Context Protocol is the common way to give an agent reach beyond the local shell, into an issue tracker, a database, a cloud API or an internal service. Each tool a server advertises carries a name, a JSON Schema for its arguments and a natural language description telling the model when to use it, so a connected server supplies capability and text the model reads on every turn.

That text is an instruction surface. A tool description can carry directions with nothing to do with the tool it describes, including how to behave before calling another server's tools, or what to include quietly in an argument. The protocol also lets a server change its tool list at runtime and notify the client, so the definitions somebody reviewed at connect time and the definitions in front of the model this morning need not be the same text. The specification is direct about the consequence, telling clients to treat a server's tool annotations as untrusted unless the server itself is trusted.

What the server can reach is the other half. A local server usually runs as a subprocess of the client under your user account, with your environment variables and your filesystem, so connecting one grants close to what installing that publisher's software grants. A remote server receives whatever the client sends, which is the arguments and, depending on the client, surrounding conversation content. The protocol also allows a server to ask the client to run a model completion on its behalf, with a system prompt the server supplies.

Servers and editor extensions are ordinary packages from registries and marketplaces where review is light, and one can be maintained honestly across a dozen clean releases before a single line changes. The install itself is code execution, because package lifecycle scripts run with your rights before the tool is ever called. Pin versions, settle what a server runs as and where it sends data before connecting it, and answer the question most asset registers cannot: which servers and extensions are connected, on whose machines, with what access. A session holding a server that reads content strangers can write alongside a server that can act on production has assembled all three conditions by configuration.

Which approvals actually reduce risk?

Most agents ask for approval before acting, and most approval designs fail the same way. The prompt describes the mechanism instead of the effect, so the developer is shown that the agent wants to run a shell command, on one wrapped line, after a long run of near identical prompts that were all fine. An approval firing on a class of action that is almost always benign trains people to clear it unread, and it manufactures a record of consent nobody gave.

The prompt has to show the resolved effect rather than a template, because a command assembled from variables tells the reader nothing about what will run, and the protocol guidance for tool calls says the same, that clients should show the real inputs before the call goes out. An allowlist written as command shapes is weak, because shells compose freely and any permitted program able to invoke another program is a bypass. Reading files inside the repository, running the test suite and formatting code need not interrupt anybody.

Bounding by credential and by network reach does not depend on predicting an attacker's syntax. The test for any proposed boundary is to assume the model has been fully convinced by hostile text and is cooperating with the attacker, then ask which controls still hold. Spend what is left of the interruption budget on actions that are hard to reverse or that leave the machine.

  • Anything that leaves the machine: outbound calls, pushes to a remote, package publishes, messages sent on your behalf.
  • Anything that touches production, including a read against a production database, because a read is how data leaves.
  • Anything that installs software, changes the agent's configuration, or edits the project instruction file it reads each session.
  • Anything that touches credentials: reading a secrets file, minting a token, altering an access policy or role assignment.
  • Anything that rewrites history, such as a force push or a branch deletion, because it destroys the record of what was done.

What changes when an agent runs in CI with nobody watching

Agents are moving into places with no operator: scheduled jobs, pipeline steps that triage failures, bots that answer issues, overnight runs that open pull requests. Approval is gone by design, so whatever the environment permits is what the agent may do, and the content it reads is now supplied by anyone who can open an issue.

The structural trap is a pipeline trigger that runs with the base repository's secrets while checking out code from a fork. The fork's contents, the pull request title, its body and its comments are attacker controlled text, and that text is exactly what the agent has been asked to read and act on. A runner in that configuration holds real credentials, usually has unrestricted outbound network access by default, and has nobody in the loop to notice the task quietly changed. Exfiltration from it needs no sophisticated channel, since a dependency install step can make a DNS request and a build can push a branch.

Give the run its own identity rather than borrowing a person's. Mint credentials that are short lived and scoped to that job, deny outbound network by default, expose no secrets to a run triggered by untrusted content, and put the human gate at merge rather than on individual steps. An agent that proposes a change for a person to review is workable, while an agent applying changes with production credentials and no reviewer has made everyone who can file an issue a trusted party.

Secrets an agent should never be able to read

The productive move is to stop trying to make the agent trustworthy and start reducing what its credentials can do. Work from a blunt assumption: every byte the agent can read may leave, and every command it can run may run. If that produces an unacceptable outcome for a particular secret, the secret should not be reachable from the machine or container the agent runs in, and the list that fails the test is short and looks much the same in most organisations.

Arranging that structurally rather than by policy takes a few decisions. Keep long lived credentials off developer workstations and mint short lived, project scoped tokens for the session, so the worst case expires on its own. Run the agent in a container that mounts the repository and little else, without the cloud token cache, without an SSH agent forwarded in, and without the browser profile. Put privileged operations behind a service the agent calls rather than a credential it holds, so policy is enforced at the point of use and the request is logged there.

Repositories accumulate secrets by accident, and an agent reading the working tree can read the history too, where the key somebody removed in a later commit is still sitting in an earlier one. A history scan across the repositories your agents work in belongs before the harder work here, because it changes which credentials you have to treat as already out.

  • Production database credentials and connection strings, including the ones in a local environment file nobody has rotated.
  • Long lived cloud access keys, particularly keys attached to a human account that carries broad rights.
  • Code signing keys and package publishing tokens, where a compromise reaches every customer who installs your software.
  • Customer data in test fixtures, seed scripts, or a production dump somebody downloaded to debug an issue.
  • Credentials belonging to other people, which is what an unlocked shared vault session on a developer machine amounts to.

What you could show after an agent incident

The question after any incident is what happened, in what order, and under whose authority. For agent activity most organisations can answer that only from a session transcript on the operator's laptop, in an unmanaged directory that rotates and will not survive a reimage.

Three changes carry most of the value. Give the agent a distinct identity so cloud sign-in logs, source control audit trails and database sessions separate its actions from the person's. Retain agent transcripts centrally with the retention you give other operational logs, and classify them as sensitive, because they contain everything the agent read. Protect the repository history as the durable record of what the agent did to your code, which means review required on the branches that matter, force push disallowed, and provenance carried in the commit.

If an agent causes personal information to be disclosed, the obligation sits with your organisation. An entity covered by the Privacy Act 1988 that suspects an eligible data breach must take all reasonable steps to complete its assessment within 30 calendar days under section 26WH(2), and where there are reasonable grounds to believe serious harm is likely it must notify the Information Commissioner and the individuals at risk. Nothing in that scheme distinguishes an act by an employee from an act by a tool the employee was running, and an assessment that cannot reconstruct what the agent read has to assume the worst. One tension is worth naming before an assessor names it: application control and restricting administrative privileges are two of the Essential Eight mitigation strategies, and a tool built to execute arbitrary commands on a workstation sits awkwardly against both.

We build software with agents in the loop and review codebases where much of the typing was done by one, so this is the posture we run rather than advice offered from a distance. It matches the rest of our work: least privilege on every identity, controls the system enforces rather than documents promising them, and a record of who did what that can be demonstrated instead of asserted. When we review an environment where agents are in use, the opening questions are the ones in this note. What does the agent hold, what can it reach, which approvals are real, and what could you show afterwards.

Know what your code would give away.

Australia-wide, from our Brisbane head office. Someone will contact you as soon as possible.

Open a briefinfo@blackshard.com.au