Published
- 22 min read
Google's ADK Workflow Bug Shows Why Agent Permissions Need Real Boundaries
Stay Safe Online Without Making It Your Second Job
The Digital Fortress (Second Edition)
A warm, plain-English guide for people with real lives and finite patience. Learn the handful of habits that genuinely protect your money, accounts, and family, and get honest permission to ignore the rest.
For People Who Cannot Afford to Get Privacy Wrong
The Anonymity Playbook (Second Edition)
A practitioner’s field manual for journalists protecting sources, whistleblowers, and activists. It explains how the surveillance actually works, what each technique costs you, and exactly where it fails.
Write, Ship, and Maintain Code Without Shipping Vulnerabilities
Secure Software Development
A hands-on security guide for developers and IT professionals who ship real software. Build, deploy, and maintain secure systems without slowing down or drowning in theory.
Use AI Coding Agents Without Losing Control of Your Codebase
The Secure Harness
A calm, practical guide to letting agents do useful work inside boundaries you set, enforce, and audit. Ships with 15 copy-pasteable artifacts: hook scripts, permission configs, release gates, and MCP templates.
Stop Shipping Demos. Start Shipping Systems.
The AI Native Engineer
Sixteen hands-on chapters, one real product. Grow it from a single model call into a retrieved, tool-using, observable, production-grade system, with evaluation treated as a habit from the first feature.
A GitHub issue should not be able to borrow the keys to your release process. That is the plain lesson from the Google ADK Python repository story published in early August 2026.
Pillar Security reported on 3 August 2026 that automated AI workflows in Google’s google/adk-python repository could be steered across a privilege boundary. A public-facing agent read untrusted GitHub text, then its output could trigger a more powerful workflow that was supposed to be reserved for trusted users. Google later hardened the repository, and public reporting does not show that the distributed ADK package was compromised. (Pillar Security)
That last sentence matters. No poisoned release quietly landed on developers’ machines. The real story sits in repository automation, identity, and the new ways AI agents can pass authority to each other when teams treat a generated comment like a trusted human action. The code package was not the weak point. The handoff was.
If your team is adding coding agents to issue triage, pull-request review, release notes, dependency updates, or CI repair, this is exactly the class of failure to study. The useful question is not whether your agent is smart. The useful question is what the agent can make the rest of your system do.
What happened, as of 5 August 2026
Google’s Agent Development Kit, often shortened to ADK, is an open-source Python toolkit for building agents. The security finding concerned the public GitHub repository behind that toolkit, not a vulnerability in the package that users install. On 4 August 2026, The Hacker News reported that Google deleted three AI agent workflows from the ADK Python repository after Pillar showed a path from a malicious public issue to a privileged code-fixing agent. (The Hacker News)
The shape was simple enough to be uncomfortable. One workflow ran when an outsider opened an issue or pull request. That agent was allowed to read public text and post analysis back into GitHub. A second workflow listened for special commands from owners, members, or collaborators. The gate checked the identity of the commenter. Pillar showed that untrusted text could influence a trusted bot account into posting the command that opened the second workflow. (Pillar Security)
The Hacker News described one issue path in concrete terms. The public issue-analyze.yml workflow ran when an issue was opened, supplied credentials and an agent to analyze the issue, then posted a generated comment through the bot account. A separate issue-fix.yml workflow listened for /adk-issue-fix comments and allowed the action when the commenter was an owner, member, or collaborator. The failure was that the bot’s trusted identity could become the bridge between untrusted text and a privileged job. (The Hacker News)
Pillar also described an earlier pull-request path involving a triage agent named adk_pr_triaging_agent. That agent could comment on, view, and label pull requests. The researchers noticed it posted as adk-bot, which they identified as a collaborator user rather than a narrow GitHub app identity. Their hypothesis was direct: if attacker-controlled pull-request text could get adk-bot to post a command such as @gemini-cli, then the attacker could cause a more privileged workflow to run with a prompt shaped by the attacker. (Pillar Security)
The most severe demonstrated impact was not theoretical approval text. In the issue-based path, Pillar said the fixing workflow tried to constrain the agent to Git and GitHub commands, but the agent could still create a payload and use Git behavior to execute it. The Hacker News reported that the team demonstrated arbitrary code execution on the CI runner and exfiltration of the bot personal access token. The same job also held a Google API key and a Google Cloud service-account credential, according to that report. (The Hacker News)
CSO Online independently reported the same key facts on 4 August 2026: Pillar found a public issue could induce an analysis agent to post a command that started a fixing workflow reserved for trusted repository users; the fixing workflow’s command limits did not prevent code execution; and Pillar demonstrated that the adk-bot personal access token could be sent from the runner to an attacker-controlled server. CSO also reported that a Google Cloud service-account key was available to the workflow. (CSO Online)
There are important limits. Public reports do not show in-the-wild exploitation, do not show a malicious ADK release, and do not show that a maintainer merged a poisoned pull request because of the agent output. The Register reported Google’s position that the finding still required maintainer action for a supply-chain compromise, did not meet the bar for a bug-bounty payout, and was recognized with credit after Google hardened the repository. (The Register)
That should lower the panic and raise the attention. The absence of a compromised release does not make the design lesson small. It makes the timing useful. Teams can fix this class of workflow before it becomes an incident record instead of a research report.
The mechanism was transitive authority
Most security reviews ask what a given identity can do. That is necessary. It is no longer enough for agentic workflows.
The missing question is what the identity can cause another identity to do. In the ADK story, the public-facing agent did not need to hold every sensitive permission itself. It needed the ability to write something trusted by a more privileged workflow. Once that downstream workflow treated the bot’s comment as an authorization signal, the first agent’s effective reach became larger than its local tool list suggested.
That is transitive authority. It is the authority that moves through comments, labels, workflow state, issue bodies, pull-request metadata, generated reviews, release notes, or any other place where one component writes and another component acts. In a classic CI system, this already matters. A label such as safe-to-test can change whether untrusted code runs. A comment command can start a job. A branch name can alter scripts. Agents add a new ingredient: the text that creates those signals may be generated from attacker-controlled input.
CSO Online quoted analyst Sanchit Vir Gogia putting the point cleanly: natural language has joined the authorization path. That is the phrase to remember. A human used to read a comment, infer intent, and decide whether to act. In an agent workflow, text may be both the content and the trigger. If a model can be persuaded to emit the trigger, your authorization check may have moved from code into prose without anyone writing that sentence in the architecture document. (CSO Online)
The mechanism is not exotic. An outside contributor opens an issue. The agent reads it because that is its job. The issue contains instructions or content crafted to change the agent’s response. The agent posts a comment as a trusted bot. Another workflow sees the trusted bot and starts a privileged job. That job has access to repository writes, pull-request operations, cloud credentials, or tokens. A system built from ordinary automation pieces becomes a delegation path.
The danger sits in the gap between two mental models. The workflow owner thinks, “Only collaborators can post this command.” The attacker thinks, “Can I make a collaborator-owned bot post it for me?” Both statements can be true at the same time. Security breaks in the space between them.
The same pattern shows up outside GitHub. A support-ticket agent can write a field that a provisioning system trusts. A Slack bot can post a command that another bot executes. A code-review agent can approve or request changes in a way that branch rules read as signal. A triage agent can label an issue as security-sensitive, release-blocking, or ready for repair. A documentation agent can alter a config file that later feeds a build. None of those actions is necessarily dangerous alone. The chain is the problem.
The Secure Harness has a blunt way to frame this: a tool that can act needs limits the tool cannot talk its way around. The agent is useful because it can read messy human text and turn it into action. That same gift makes it a bad place to enforce the boundary by itself.
Why bot identity matters more than prompt wording
A prompt can tell an agent not to trigger privileged workflows. A bot identity can make that instruction unnecessary by lacking the power to do so. Prefer the second design.
Pillar’s research called out the use of a collaborator-style bot identity and long-lived personal access tokens. In their description, adk-bot behaved like a trusted account inside the repository. That meant a comment from the bot carried the weight of a collaborator comment, even when the words in that comment were shaped by untrusted input. (Pillar Security)
This is a familiar mistake in a new costume. Teams used to give CI systems broad tokens because it made automation easy. Then those tokens leaked through logs, build scripts, third-party actions, or compromised dependencies. The lesson was painful but clear: use short-lived credentials, narrow scopes, named identities, protected environments, and approval gates for dangerous actions. Agent workflows need the same treatment, with one extra rule: assume the agent may repeat attacker-controlled words.
A human collaborator is accountable for intent. A bot is accountable for policy. When the bot reads public text and writes back to the repository, its identity should reflect that job. It should be able to label a pull request if labeling is required. It should not be able to satisfy a command gate for code-modifying workflows unless a separate authorization path proves that a trusted human asked for it.
That difference sounds small until an incident. If a bot can label issues only in a narrow namespace, the worst case is messy triage. If the same bot can trigger a repair agent, push a branch, open pull requests, and carry cloud credentials in the runner, the worst case changes shape. The attacker no longer needs the triage bot to be powerful in every direction. The attacker needs the triage bot to be believed by something that is powerful.
The right identity design starts by splitting jobs. The public issue reader gets one identity. The pull-request labeler gets another. The code-fixing workflow gets a separate identity that can be triggered only by an event an outsider cannot create through model output. The release workflow gets a still narrower route. Each identity has a small, boring permission set and a clear owner.
GitHub apps are often a better fit than human-like personal access tokens because their permissions can be scoped and audited more naturally. Short-lived tokens are better than long-lived ones because leakage has a smaller window. Repository environments with required reviewers are better than plain workflow secrets because a sensitive job can require a human approval step. None of these controls is new. Agents make them harder to skip.
The key test is simple: if an attacker controls every word the public-facing agent reads, what trusted actions can still happen? If the answer includes code execution, token access, package publication, cloud writes, production deploys, or privileged comments, the identity model is carrying too much trust.
Command filters are weak when the agent can write files
The ADK issue path included a detail every engineer should sit with. The privileged job tried to limit what could be executed. The runner allowed only commands whose first token was gh or git, according to The Hacker News. That sounds safer than a shell. Pillar still found a path to code execution by combining file writes with Git behavior. (The Hacker News)
This is the difference between filtering a command string and controlling capability. If an agent can write files and run Git, it may be able to influence hooks, config, paths, submodules, attributes, or helper behavior. Git is a powerful program, not a harmless verb. GitHub’s own documentation describes hooks as executable programs and allows core.hooksPath to point to another hooks directory. A tool allowlist that says “Git is allowed” still gives the agent a rich surface if the workspace is writable. (Git documentation)
The same trap appears with many “safe” tools. python -m sounds safer than a shell until the workspace controls import paths. npm test sounds routine until package scripts run arbitrary commands. make docs sounds harmless until the Makefile belongs to an untrusted branch. terraform plan sounds read-only until providers and modules come from places you did not pin. gh pr comment sounds like communication until another workflow treats the comment as a command.
Agents are especially good at finding these seams because they can reason across documentation, tool output, and filesystem state. That is useful when the task is to repair a build. It is risky when the policy is a thin wrapper around a tool with hidden execution paths. A syntactic allowlist gives a false sense of control if the allowed program can be influenced into doing work outside the policy’s intent.
The safer pattern is capability separation. The job that reads untrusted text should not share a writable workspace with secrets. The job that can write files should not have cloud credentials unless the write path is trusted. The job that can run tools should run in a sandbox with no long-lived tokens and no route to production. The job that carries sensitive credentials should read from trusted inputs only, or require an approval event that comes from outside the agent’s generated text.
When teams hear “sandbox,” they often picture a container. A container helps, but it does not answer the whole question. The real boundary includes tokens, network access, mounted files, workflow permissions, artifact upload rights, package registry credentials, cache keys, and downstream events. If the container can exfiltrate a token to the internet, the container mostly made the token theft tidier.
That is why the plain-English phrase matters: the computer still had a way out. You do not need to teach every engineer the word egress before they understand the risk. If a workflow holds a secret and can make an outbound request, a prompt-injected agent may be able to send the secret away. If a workflow can write a comment that starts another job, a prompt-injected agent may be able to hand work to a more powerful machine. Start there.
Human review still matters, but do not hide behind it
Google’s reported position, as described by The Register, was that a full supply-chain compromise still required a maintainer to merge the malicious pull request. That is an important defense. Branch protection, required review, and human merge steps are exactly the controls that stop a bad automation path from becoming a bad release. (The Register)
The mistake would be treating human review as an excuse to leave the agent path messy. Reviewers are busy. They use signals. A bot review, a generated approval, a label, a green check, a friendly comment, and a passing workflow all shape how a human reads the page. Pillar’s pull-request scenario focused on manufacturing a believable trail around a poisoned PR: a human-style request, a bot action, an apparent review path, and a final decision left to the maintainer. (Pillar Security)
That does not mean reviewers are helpless. It means the system around them should not create fake confidence. A human gate is strongest when the evidence shown to the human is trustworthy. It is weaker when the same untrusted text that introduced the risk can also generate the evidence that says the risk was handled.
Many teams will get agent adoption wrong at this exact point. They will keep the formal human approval step, then let agents generate the surrounding proof. The agent writes the review summary. The agent labels the PR. The agent explains why tests pass. The agent suggests the merge. The agent opens the follow-up issue. The human clicks last, but the human’s context was shaped by the same system under attack.
A better design separates assistance from authorization. Let the agent summarize a diff, but make clear that the summary is advisory. It can propose labels, but labels that trigger sensitive workflows should come from a trusted path. It can draft a fix, but the fix should stay in a low-trust environment until a human explicitly promotes it. Review recommendations belong in the same bucket: useful context, not required approval.
Also make bot output visually and semantically distinct. A collaborator-like username can be convenient, but it blurs the line between human intent and automated text. Use names that say what the bot is, not what you wish the bot felt like. Include run IDs, source events, and permission class in bot comments. A comment that says “generated from untrusted issue text, no authorization implied” is less elegant than a cheerful bot persona. Safer too.
The human should remain in the loop for high-impact changes. The system should also make the loop worth something. A rubber-stamp screen surrounded by model-generated confidence is ceremony, not control.
What to check in your own repositories this week
You do not need to use Google’s ADK to have this problem. Any repository with AI-assisted triage, review, fixing, release, or dependency automation can grow the same shape. The review below is meant to be finished, not admired.
-
List every agentic workflow: Search for workflows and apps that call language models, coding agents, MCP servers, browser tools, or AI review services. Include GitHub Actions, GitLab CI, Buildkite, Jenkins, bots, scheduled jobs, and external SaaS integrations. Note which ones run on public issues, public pull requests, comments, emails, support tickets, or external documents.
-
Mark the untrusted input points: For each workflow, write down exactly what attacker-controlled text it reads. Issue title. Issue body. Pull-request description. Diff content. Comments. Commit messages. File contents. Artifact names. Labels proposed by outsiders. Treat all of it as hostile, even when the contributor looks polite.
-
Trace what the agent can write: Comments, labels, reviews, commits, branches, status checks, artifacts, release notes, discussion replies, and workflow commands all count. Pay special attention to anything another workflow reads. The dangerous object may be a plain comment that starts with the right command word.
-
Trace downstream triggers: Search for workflows triggered by
issue_comment,pull_request_review,workflow_run, labels, status checks, repository dispatch, artifact creation, or comment commands. Ask whether a public-facing agent can create any of those triggers directly or indirectly. If yes, assume the public agent’s effective privilege includes the downstream job until you prove otherwise. -
Inspect every token and secret: Identify personal access tokens, cloud keys, package-registry tokens, GitHub app tokens, deploy keys, and repository secrets available to agent jobs. Replace human-like personal access tokens where possible. Narrow scopes. Shorten lifetime. Remove secrets from jobs that process untrusted text.
-
Break command gates on purpose: If a workflow says only
gitandghare allowed, test whether writable files, hooks, config, aliases, submodules, or helper programs can still cause code execution. Do this in a test repository. The point is not to become clever. The point is to stop relying on filters that crumble under normal tool behavior. -
Require an authorization signal the agent cannot forge: Sensitive jobs should start from a trusted event outside generated text. Examples include a protected environment approval, a maintainer action recorded by the platform, a signed command checked against a human identity, or a workflow dispatch with approved inputs. A bot comment derived from public text should not count.
-
Keep branch protection boring and strict: Required human review, CODEOWNERS, signed commits where appropriate, required status checks, restricted push rights, and protected release branches still matter. Do not remove them because an agent seems careful. The agent’s carefulness is not a substitute for a release boundary.
This review produces a map. The map should show not only which identity owns which permission, but how authority moves. Inventory records what exists. Delegation mapping records what can happen after one trusted component reads another component’s output.
If the map gets messy, start with the highest-impact paths. Which agent can influence code that ships? Which one can reach secrets? Which one can trigger a runner with network access? Which one can affect a package release? Which one can alter security labels or approvals? Fix those before arguing about every low-risk label bot.
How to design the safer pattern
The safer pattern supports agents by giving them real boundaries. Agents are useful because they can handle ambiguous work. Boundaries are useful because they turn ambiguous work into bounded damage when the agent guesses wrong.
Start with separate identities. A public triage agent should have a public-triage identity. It should read issues and write comments or low-risk labels. It should not be a collaborator-shaped account whose comments satisfy privileged gates. A repair agent should have a repair identity. A release agent should have a release identity. Each identity should be named, logged, owned, and scoped to the smallest useful set of actions.
Then separate environments. A job that consumes untrusted text should run in a low-trust environment with no sensitive secrets. If it needs to propose a code change, have it produce a patch artifact or a branch in a fork with limited permissions. A second, trusted job can pick up the artifact only after a human or policy gate approves the promotion. This feels slower on paper. In practice, it gives you a clean place to inspect and stop.
Next, separate communication from control. Agents can write comments all day. Comments should not be the root of authority unless the platform can prove the commenter is a trusted human and the content was not generated by a public-text agent. If you must use comment commands, check the actor, the event source, the workflow origin, and the permission class. Do not trust a command just because the username is familiar.
Use explicit policy files for sensitive actions. Which labels can the agent apply? Which paths can it edit? Which commands can it request? Which registries can it publish to? Which cloud projects can it touch? Put those answers in code, not only in a system prompt. The prompt can explain the rules. The tool layer should enforce them.
Treat network access as a permission. If a runner has secrets, default its outbound network to deny or route it through a controlled proxy. If a job needs package downloads, use pinned sources and mirrors where practical. If a job needs to call GitHub, cloud APIs, or package registries, give it only those destinations. The phrase “what leaves the lab” should be part of every agent review, because exfiltration often starts as an ordinary HTTP request.
Log the delegation path. When Agent A writes a comment that Agent B reads, the audit trail should show both sides. Source event, source actor, generated content hash, workflow run ID, downstream trigger, downstream identity, and approval state should be visible in one place. Without that, incident response becomes archaeology.
Finally, test the failure. Put a harmless prompt injection in a test issue and see whether your triage bot repeats a command. Try to make a public-facing agent label something release-ready. Try to make a review bot emit a phrase that starts another workflow. Try to make a command-filtered job execute code through an allowed tool. You are not testing whether the model is obedient. You are testing whether disobedience can travel.
The best outcome is boring: the agent gets confused, writes a weird comment, and nothing privileged happens. That is what a real boundary looks like.
The larger lesson for AI engineering teams
The ADK repository finding belongs beside the broader run of 2026 agent-security stories, but it teaches a different lesson from the loudest headlines. Rather than a model escaping a sandbox, the core problem was a system believing the wrong message.
That distinction matters for working engineers. You can spend months debating model behavior and still miss the GitHub comment that starts a privileged workflow. You can write a careful system prompt and still hand the agent a token that can do too much. You can disable shell access and still allow a tool with hidden execution paths. You can keep human review and still surround the human with generated signals that look more authoritative than they are.
The practical frame is smaller and stronger: model the agent as a persuadable actor with tools. Then model the tools, identities, environments, and downstream triggers as the security boundary. The agent may behave well most of the time. The boundary exists for the other times.
This will become a normal part of software engineering. Agentic CI will triage bugs, repair tests, update dependencies, write migrations, draft release notes, and chase flaky failures. Teams will keep using it because the productivity gain is real. The security answer cannot be “never use agents in the pipeline.” The answer is to stop letting public text become private authority.
That means the boring controls win again. Narrow identities. Short-lived tokens. Separate jobs. Protected environments. Human approval for high-impact actions. Low-trust runners for untrusted input. Network limits. Logs that show delegation, not only login events. Branch protection that agents assist but cannot fake.
The memorable phrase from this incident is simple: the trusted bot became the bridge. If a public issue can convince your trusted bot to carry a command across a boundary, you do not have a boundary. You have a polite request.
Cyber Security in Plain English sends one email per month. If you want the practical version of stories like this without the panic, sign up for the newsletter on the site.
Sources
- Pillar Security: I’ll Just Call You: Agent-to-Agent Privilege Boundary Failures in CI/CD on Google’s ADK Repository, accessed 2026-08-05
- The Hacker News: Google Deletes 3 ADK AI Workflows After Malicious GitHub Issue Could Trigger Privileged Agent, accessed 2026-08-05
- CSO Online: Google ADK flaws reveal what happens when AI agents trust the wrong message, accessed 2026-08-05
- The Register: Google dev kit spurs first-ever agent-on-agent violence, accessed 2026-08-05
- Git documentation: Git hooks, accessed 2026-08-05