A startup just raised $50 million to police AI agent credentials. Here's how to scope tokens, deploy keys, and secrets yourself.
A coding agent's credentials should be scoped to exactly what its current task needs, nothing more. Most teams instead wire one up the same way they set up a laptop for a new hire: hand it a token, point it at the repository, and move on. The difference is that a new hire notices when something feels off. An agent reading a poisoned README, a booby-trapped issue, or a malicious dependency has no such instinct built in, and it will use whatever credentials it holds exactly as instructed, including when the instruction came from an attacker.
The default token is almost always too wide
When a team connects Claude Code, Cursor, or any other agent to GitHub, the fastest path is a personal access token from whoever set it up. Classic PATs carry the repo scope, which grants read and write access to every repository the account can see, public and private, across every organization that account belongs to. An agent doing one task in one repository ends up holding a key to the whole building.
The same shortcut shows up with deploy keys and CI credentials. A single SSH key gets added to a dozen repositories because it is already set up. An admin-level automation token gets reused for a script that only ever needed to open a pull request. None of this is scoped to the task; it is scoped to convenience, and convenience is exactly what an attacker exploiting an agent is counting on.
Why agents need tighter scoping than humans doing the same job
A human developer holding a broad token is still a check on misuse. They read a pull request before merging it, they notice a dependency name that looks off, and they pause when an issue asks for something unusual. An agent processing that same content does not have that pause built in by default. It treats a comment in a file, a line in an issue, or a package's install script as just more text to act on, using whatever credentials it already holds for the legitimate task in front of it.
The GitSpawn disclosure in September 2026 showed exactly how that plays out. A malicious value set in a repository's own .git/config, through the core.fsmonitor option, runs as an external command every time Git refreshes its index. Coding agents call git status and git diff constantly in the background to track what changed, and those routine calls triggered the attacker's command with no approval prompt and nothing shown on screen. Claude Code, Codex, Cursor, Grok Build, Goose, Hermes Agent, and Qwen Code were all affected. Researchers disclosed eight distinct flaws across those seven tools, four of them still unpatched at the time of publication, though no confirmed exploitation in the wild had surfaced.
Sources: The Hacker News: Malicious .git Configs Can Make Claude, Codex, Cursor, and Other AI Agents Run Attacker Code, Manifold Security: GitSpawn
The market is already pricing in this risk. AIR Security emerged from stealth in September 2026 with fifty million dollars in funding led by Sequoia Capital and Greenoaks to build what its founders describe as a firewall for AI agents, screening the skills, plugins, and MCP servers an agent installs for excessive permissions and hidden instructions before they run. The pitch only makes sense because the underlying problem, an agent using its own valid access in a way nobody intended, is now common enough to fund a company around.
Sources: SecurityWeek: AI Agent Firewall Startup AIR Security Emerges From Stealth With $50 Million
Scope the token to the task, not the developer
GitHub's fine-grained personal access tokens exist for this. Instead of one classic repo scope covering everything, a fine-grained token is tied to a specific set of repositories and a specific set of permissions inside them: contents, pull requests, issues, actions, and more, each grantable independently and each settable to read-only where write access is not needed. A token scoped this way that leaks or gets misused can only touch what it was explicitly given.
Sources: GitHub Blog: Introducing fine-grained personal access tokens for GitHub
- Pick the exact repositories the agent's task touches. Never leave it on "all repositories" as a default.
- Grant the narrowest permission per resource: read-only for content the agent only inspects, write only where it opens commits or PRs.
- Set an expiration measured in days or weeks, not "no expiration," and put renewal on a calendar rather than relying on memory.
- Skip organization-owner or admin scopes entirely. An agent doing code review or opening PRs never needs them.
- Where the platform supports it, require organization-admin approval before a new fine-grained token can reach the org's repositories.
Deploy keys: one repository, read-only by default
Deploy keys are already built around this constraint when used correctly. A GitHub deploy key attaches to a single repository, not an account or an organization, and new deploy keys default to read-only; write access has to be turned on deliberately. That single-repository ceiling is why a leaked deploy key does not cascade into every other project the same team owns. Reusing one SSH key across many repositories defeats the point of using deploy keys at all.
Sources: GitHub Docs: Managing deploy keys
GitLab's equivalents are the project access token and the deploy token, both scoped to a single project, or a single group for the group-level variant, with their own permission list and expiration date, and neither tied to a person's account. The naming differs between platforms, but the shape of the fix is identical: scope the credential to the smallest unit of work that actually has to happen, not to the person or team running it.
Sources: GitLab Docs: Deploy tokens
The same rule applies to deploy secrets, not just Git tokens
Least privilege does not stop at source control. An agent that can trigger a deployment usually holds a cloud credential too: an AWS access key, a Vercel or Firebase deploy token, a Kubernetes service account. The failure shows up in a different shape but the same root cause: a personal AWS key with broad IAM permissions gets pasted into a CI secret and reused for every pipeline, because provisioning a narrower one takes more setup than reusing what already exists.
The fix here mirrors the one on the Git side. Give the agent a role scoped to the one environment and the one set of actions its task needs: deploy access to a staging bucket, not read and write on every bucket in the account. AWS's own guidance pushes this further with temporary security credentials issued through STS, which expire automatically after a set window, often as short as fifteen to thirty minutes for a single job, instead of the static access key that stays valid until someone remembers to revoke it. A credential an agent accidentally writes to a log file stops being useful within minutes rather than indefinitely.
Sources: AWS IAM User Guide: Temporary security credentials
- Give an agent a separate credential per environment; a staging deploy key should never also reach production.
- Prefer short-lived, auto-expiring session credentials over static keys wherever the platform supports them.
- Scope IAM roles and service accounts to the specific actions a task needs, not a managed "admin" or "editor" policy applied out of convenience.
| Capability | Classic PAT | Fine-grained PAT | GitHub App token |
|---|---|---|---|
| Scope | Every repo the account can see | Selected repositories only | Repos the app is installed on |
| Permissions | All-or-nothing repo access | Per-permission, e.g. contents or issues alone | Per-permission, set at install time |
| Lifetime | Can be set to never expire | Expiration required or org-enforced | Short-lived, refreshed automatically |
| Blast radius if leaked | Entire account, every org membership | Only the selected repositories | Only that installation, revocable instantly |
Rotate on a schedule, and immediately on any doubt
Rotation should already be routine before anything goes wrong: short-lived tokens, a renewal date on the calendar, and the old token revoked the moment a new one is issued rather than left active as a backup. That habit is what makes the second kind of rotation, the emergency kind, fast instead of a scramble.
An agent's credentials should be treated as exposed the moment there is a plausible path to it, not only after confirmation. A prompt-injection attempt found in an issue or file the agent read, a dependency pulled from an unfamiliar registry, or a supply-chain alert on a package inside the agent's project are all reasons to rotate, even without proof anything was actually used.
- Revoke the token or deploy key immediately. Do not wait to confirm misuse first.
- Check access logs for the exact window the credential was live, not just the moment the incident was noticed.
- Rotate every secret that credential could reach, including chained ones like a CI variable it could read, not just the token itself.
- Reissue with a narrower scope than before. An incident is the moment to fix over-provisioning, not just replace it.
- Confirm the agent's task actually needs the new token's scope before handing it over again.
Detection helps close the gap between rotation cycles. GitHub's secret-scanning push protection, generally available since May 2023, blocks a commit that contains a recognizable token or key pattern before it ever reaches the remote, catching the case where an agent tries to write a live credential into a file it is committing. It is not a substitute for scoping the token correctly in the first place, but it closes one specific failure mode: a secret ending up somewhere it should never have been typed.
Scoping is necessary, not sufficient
None of this stops an agent from making a bad change within the access it was correctly given. A narrowly scoped token still lets an agent add a dependency that looks legitimate and is not, quietly widen a workflow file's own permissions, or open a PR that reads as routine and is not. That is a different layer of the problem, and it is the one TLM Forge is built for. It runs adversarial reviewers, including a red-team pass on the diff, and blocks the merge until every critical finding is resolved, regardless of which credential produced the change. Scoping limits what an agent can reach. A merge gate catches what it did with that reach.
A token an agent has never needed cannot be the one that gets it, or you, compromised.
Frequently asked questions
01What is the difference between a classic and a fine-grained GitHub PAT?
A classic personal access token uses broad scopes like repo, granting access to every repository the account can see. A fine-grained token is limited to specific repositories and specific permissions within them, so a leak or misuse only reaches what was explicitly granted.
02Should an AI coding agent use a token tied to a human's personal account?
No. A personal token inherits everything that person can access, almost always broader than one task needs. Use a repository-scoped fine-grained token, a deploy key, or a GitHub App installation token instead, none of which carry an individual's full account access.
03How often should a coding agent's token or deploy key be rotated?
Set an expiration measured in weeks, not months, and rotate on that schedule even without incident. Rotate immediately, outside the schedule, whenever there is a plausible reason the credential was exposed, such as a suspicious dependency or a prompt-injection attempt.
04What should you do if an agent's credentials may have been exposed?
Revoke the credential first, before confirming misuse. Then check access logs for the exposure window, rotate any other secret that credential could reach, and reissue a replacement scoped narrower than the one it replaces.
05Can prompt injection make an agent misuse its own valid, unstolen credentials?
Yes. The credential does not need to be stolen. An instruction hidden in a file, issue, or dependency the agent reads can direct it to use its existing valid access in a way nobody intended, which is why the access itself needs to stay narrow regardless of how trustworthy its origin seems.