Menu
Back to Blog
AI SecurityCode Audit

How a Stranger's PR Comment Could Steer an AI Agent: Two Findings from Our Open Session Review

On a public repository, anyone with a GitHub account could leave a review comment that Open Session would deliver into a teammate's agent session as an instruction. That session had admin-level tools.

We found this, and a second, smaller issue, during a static security review of Open Session. We reported both privately. Tella fixed them and published the advisories the same day, and agreed that we could name both advisories here.

What Open Session is

Open Session is an open-source, self-hosted server by Tella for running AI agent sessions. Sessions can open pull requests. A GitHub App can run automatic reviews of those pull requests. Runners are attached machines where sessions run commands.

We reviewed the opensession-server package at commit f4de85b.

Finding 1 (High): review comments from anyone became instructions

The advisory is GHSA-72p4-vh42-4f92. The review handoff collected comments from every GitHub login on the PR, with no filter on who wrote them.

The path, step by step:

  1. A team runs Open Session with the GitHub App on a public repository. A teammate's session opened a PR and is still the latest session on that branch.
  2. An outside account leaves an inline review comment on a current line of that PR. The comment is written as a review finding and contains an instruction.
  3. The next automatic review of the PR is unsatisfied. The handoff collects comments from every login, including the outsider's, together with the real findings.
  4. The handoff queues them into the teammate's session as a "GitHub" turn that says to address every actionable finding.

The outside account needs no access to the Open Session instance. Comment text was capped at 400 and 600 characters, which is enough for an instruction. The handoff was on by default, with OPENSESSION_REVIEW_HANDOFF=0 as the kill switch.

Why it matters: the receiving session is interactive, so it holds the interactive-only MCP servers. These are opensession-admin, an unrestricted opensession-sessions and opensession-runners. The session also has a shell in the worktree and can run commands on attached Runners. SECURITY.md withholds exactly this set from automation-owned sessions, because they process untrusted text.

The most telling part is that the codebase already treated these same people as untrusted, in three other places:

  • Webhook intake drops a PR review notification from a login that is not on the team roster.
  • isTrustedGithubLogin says outside contributors are not automatically allowed to command the GitHub agent.
  • The read-only review path, in agents/github/review-context.ts, labels the same PR text "untrusted data".

The check existed. It was applied to who triggered the run, not to the content fed into it.

This is a prompt injection path, but we reported it as a code issue: untrusted input reaching privileged capability. We did not report it as a model that can be talked into saying something.

Fixed in 6ac2fd370.

What we did not prove

This was a static review, and the advisory states its limits. We repeat them here:

  • We did not run anything. Nothing was executed, and nothing was sent to any live instance or to any PR.
  • We did not test whether a given model follows the injected instruction.
  • We could not confirm from the repository alone whether automatic PR review is enabled by default for a configured repo.
  • The injected turn is queued behind a pending human request. It is delayed, not blocked.

Finding 2 (Low): a network check that could not fail

The advisory is GHSA-w23q-r2q7-vrrc. The security policy lists registering a Runner from outside the tailnet as a boundary, and the docs say pairing is tailnet-gated. In every shipped install, a built-in gateway proxy sits in front of the backend and connects to it on loopback. So the backend always sees the connection as coming from 127.0.0.1, and loopback counts as tailnet.

The result was two routes with two different problems. The Runner WebSocket route always passed the check. The register and heartbeat routes trusted an X-Forwarded-For header that the client controls.

This was a defense-in-depth gap, not a full bypass, which is why it was rated Low. Registering still needed a pairing code: 8 characters, single-use, valid for 10 minutes. The WebSocket route still needed a valid Runner token. In the recommended setup the proxy binds a tailnet address, so the gap changes nothing in practice. The point is the gap between what the policy says and what the code enforces.

Fixed in 12e46aa33.

What to check in your own agent product

If you build an AI agent product, or let an AI coding agent act on your repositories, these checks apply directly:

  • Check trust on content, not only on the trigger. Who started the run is not the same as who wrote the text the agent reads.
  • Mark outside text as untrusted data, keep the author attached, and keep it away from "do this" instructions. Open Session's own read-only review path already did this.
  • Do not give admin or command tools to a turn that carries text from outside your team. Open Session's SECURITY.md draws this line for automation-owned sessions. The handoff turn crossed it.
  • If the app sits behind a proxy, make sure it sees the real client address, and ignore X-Forwarded-For unless a known proxy sets it. Otherwise a check on the client address can pass for every client, as it did in finding 2.
  • Compare what your SECURITY.md and docs promise with what the code enforces. Buyers and auditors read the docs.

How we work

We read SECURITY.md first, so we know what the project itself claims to protect. We review the code statically and tie each finding to specific files and lines. We report through the project's private vulnerability reporting channel, and we publish only after the fix, with the vendor's permission. We use the same approach, reading the code by hand and tying every finding to a file and line, in paid audits like this production readiness audit.

Both advisories were reported, fixed and published on October 7, 2026. Thank you to the Tella team for taking the report seriously and fixing both issues the same day.

FAQ

Is this a model problem or a code problem?

A code problem. The path delivered untrusted text, with an instruction to act on it, into a session that held privileged tools. We did not test whether any model follows the injected instruction.

Was anyone affected?

We do not know. This was a static review, and we did not run anything against any instance. We have no information about whether the path was ever used.

How do I check my own agent product for this?

Trace every place where text from outside your team enters a prompt, and check which tools the agent holds in that turn. That is the core of an AI agent security review.

We review AI agent products and AI-generated codebases the same way, by hand, with findings tied to specific files. If you are building one, tell us about it.