Safeguard
Application Security•

How do you stop a poisoned pull request from running in TeamCity?

A fork pull request can run code on your TeamCity agent. Learn the three controls JetBrains documents: author filters, trigger rules, Untrusted Builds.

Safeguard Security Team
5 min read

A pull request from a fork can run its own code on your TeamCity agent if your triggers build it automatically. JetBrains documents three controls: filter pull requests by author, keep triggers from matching pull request branches, and set Untrusted Builds to cancel or require approval for changes from external users.

How does a poisoned pull request work in TeamCity?

JetBrains explains the risk in its Pull Requests page. If a build configuration targets a public repository where untrusted users can create pull requests, building those changes means TeamCity can execute malicious code from them. Two examples are given: a harmful service message sent from the source code, and altered project settings from a modified .teamcity folder.

A build step runs as the OS user of the agent. JetBrains' security notes say that anyone who can change code used in builds, including committers on any branch or pull request that TeamCity builds, can do what that agent user can do. That includes reading other projects built on the same agent and publishing artifacts that other builds use.

The Pull Requests feature does not trigger builds by itself. A VCS trigger does that. New build configurations created in the UI include a trigger with the +:* branch rule, which lets TeamCity build pull request branches. That default is where the exposure often starts.

What are the three controls?

JetBrains' Untrusted Builds page lists them, in increasing strength.

  1. Change the trigger branch rules so pull request branches are not built automatically. JetBrains notes this is only a partial fix, because a user with permission to run builds can still start one by hand without a code review.
  2. Filter by author in the Pull Requests feature. This cuts off external users' requests completely, so their branches are not visible to TeamCity.
  3. Configure Untrusted Builds at the project level. The default action can be Do nothing, Cancel build, or Require approval. With approval, builds with external changes are queued until the required number of named reviewers approve. This applies to builds started by a trigger and to builds started by a person. Untrusted Builds currently support GitHub and GitLab.

You can set approval rules by user or by group with a vote count, and a timeout that cancels builds nobody verified. TeamCity can also log untrusted builds in the build log and in teamcity-server.log with the reason, such as a pull request from a fork in a public repository.

Note the distinction JetBrains draws: Untrusted Builds and Build Approval are separate features. Build Approval avoids needless or expensive builds. Untrusted Builds blocks harmful changes from external authors.

What should the agent be allowed to hold?

Even with approval in place, assume a build can go wrong. JetBrains advises storing secrets in parameters of the password type, restricting who can trigger deployment builds, disallowing personal builds in deployment chains, and using a separate pool of clean agents for them. Keep untrusted pull request builds on agents that hold no deployment credentials.

Constructed example: a public library builds all pull requests on the same agent pool that runs its release build. A first-time contributor opens a pull request that edits the build script. The agent runs it. The release signing key is available to that agent user. Separating pools, or setting Untrusted Builds to require approval, breaks the chain.

What to do

  1. Find every build configuration that points at a public repository or accepts forks.
  2. Check each VCS trigger and VCS root branch specification for rules that match pull request branches.
  3. In the Pull Requests feature, filter by author to trusted users where you can.
  4. In project settings, open Untrusted builds and choose Require approval or Cancel build.
  5. Name approvers by group, set a vote count and a timeout.
  6. Move pull request builds to agents with no secrets, and keep release builds on a separate pool.
  7. Review changes to the .teamcity folder like code that runs with privilege.
  8. Keep TeamCity itself current. JetBrains downloads critical security updates automatically, but an administrator must still approve installation.

For the code under review, Safeguard policy gates on pull requests can add a check before merge, but that does not replace isolating the build agent.

Quick check

Does the Pull Requests feature build pull requests automatically?

No. It shows them and filters them. A VCS trigger starts the build, and the default trigger in new configurations can match pull request branches.

Is cancelling the trigger enough?

JetBrains says it is not complete protection, since users with permission to run builds can start them manually. Untrusted Builds covers manual starts too.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.