Block and Fix in the Same Pull Request: The PR Security Gate

Blocking a risky change is the easy part. Keeping the gate turned on means helping fix what it blocks.
A PR security gate that blocks and walks away gets switched off. Here is how to pair blocking with validated auto-fixes on the same pull request.
July 20, 2026

A PR security gate has one job: stop a risky change from merging. Most gates do that job and then stop. The pull request goes red, the developer gets a list of findings, and the fix becomes their problem. Sometimes they fix it. Sometimes they ask for an exception. Sometimes the gate gets switched to "warn" because it slowed a release.

That last outcome is the one that should worry a security leader. A gate that blocks without helping teaches engineering to route around it. The problem is not blocking. The problem is blocking and walking away.

This post covers what a PR security gate should do once it has blocked a pull request, why pairing the block with an automated fix changes how teams experience guardrails, and where the limits of that pairing are.

What a PR security gate is for

A PR security gate, sometimes called a pull request guardrail or merge check, evaluates the change before it lands on a protected branch. It can check for newly introduced code weaknesses, vulnerable or unpinned dependencies, secrets, license violations and infrastructure misconfigurations. The result is a status check that passes, warns or fails.

The pull request is the right place for this for a simple reason: it is the last point where fixing something costs only the author's time. After merge, the same issue becomes a finding in a backlog, gets triaged, gets assigned, gets a ticket and waits. Every hop adds delay and loses context.

Two rules make a gate usable in practice:

  • Only fire on what the change introduces. Compare the branch against a baseline of the default branch, so the existing backlog never blocks an unrelated pull request. A gate that fails because of a finding from 2022 is a gate people disable.
  • Start in observe mode. Record what would have been blocked before you block anything. Then warn. Then block, once you know the false-positive rate is tolerable.

Why block-only gates erode

A block-only gate converts a security finding into a developer task with no help attached. The developer now has to understand the weakness class, find the right remediation pattern, apply it without breaking behavior and push again. For a senior engineer who has seen SQL injection a hundred times, that takes minutes. For everyone else, it can take an afternoon, and the afternoon is spent on work that was not on anyone's plan.

Multiply that by every blocked pull request and the gate starts to feel like a tax. The predictable responses follow:

  • Exception requests that security has to review one by one.
  • Pressure to lower severity thresholds until the gate rarely fires.
  • Quiet moves from "block" to "warn", which in practice means "ignore".
  • Findings fixed with the smallest possible change that makes the check pass, which is not always the correct fix.

None of this is bad faith. It is people optimizing for the work they were actually asked to ship.

Block and fix in the same pull request

The alternative is a gate that blocks and then offers the fix, on the same pull request, before the developer has context-switched away. The sequence looks like this:

  1. The guardrail evaluates the pull request and finds a new, eligible finding.
  2. It blocks, and the summary says how many of the blocking findings can be fixed automatically.
  3. A fix is generated for the eligible findings and applied to the pull request's own branch.
  4. The change is build-validated, and the guardrail re-evaluates.
  5. The check flips to passing, and the violation shows as resolved on that pull request.

The developer's experience changes from "you have a security problem" to "you had a security problem, here is the fix, review it". The block still happened. The unsafe code still did not merge. What changed is who did the remediation work.

What "eligible" should mean

Auto-fixing inside a pull request is only responsible when the fix is predictable and safe. For dependency findings that usually means a direct dependency with a fix version available, so the change is a version upgrade in the right manifest. For code findings it means the finding matches a known fix pattern with a high-confidence, deterministic fix, such as parameterizing a query, escaping output, allowlisting input or normalizing a path.

Everything else should go to manual review with guidance: transitive vulnerabilities where the right upgrade path is a judgment call, hygiene violations, and code findings without a high-confidence fix. The honest answer "this one needs a person" keeps trust in the ones that do not.

When the fix does not build

The failure path matters as much as the happy path. If the generated change does not build, it must not be pushed. The right behavior is to leave a comment on the pull request explaining what was attempted, keep the violation active and route it to manual review. A gate that pushes broken code to unblock itself has traded one problem for a worse one.

Where fixes land: suggestion, commit or new pull request

How the fix reaches the pull request depends on the platform and on branch protection:

  • Inline suggestion. On GitHub, a small change to existing lines can be offered as a one-click "Apply suggestion" block, so the author decides whether to accept it.
  • Direct commit. Larger changes, new lines or other platforms get a commit on the branch with a comment explaining it.
  • A new pull request. When the target branch forbids direct pushes, the fix should arrive as its own pull request against the blocked branch, so branch protection stays intact and the fix goes through review like any other change.

The principle behind all three: the fix goes back to the pull request that was blocked, and it never bypasses your review rules.

A worked example

A developer adds an endpoint that looks up orders by a query parameter and builds the SQL with string formatting:

query = f"SELECT id, total FROM orders WHERE status = '{status}'"

The PR security gate runs. The static analysis trace shows status comes from the request and reaches the query unmodified. The guardrail is set to block high-severity injection findings, so the check fails. The summary reports one blocking finding, and marks it auto-fixable.

The fix is a parameterize fix:

cursor.execute("SELECT id, total FROM orders WHERE status = %s", (status,))

It is applied to the branch, the build passes, the guardrail re-runs and the check goes green. The developer reviews a two-line diff and merges. Total security involvement: none. Total delay: the length of one CI run.

If the same pull request had also introduced a transitive vulnerability with no clean upgrade path, that finding would stay blocking, with remediation guidance attached, and the developer would handle it by hand. One auto-fix does not mean every finding gets one.

Designing a PR security gate that teams keep turned on

Whether or not you automate fixes, these choices decide whether a gate survives contact with engineering:

  • Baseline against the default branch. Fire only on new findings.
  • Scope deliberately. Block on tier-one services and production branches first. Warn elsewhere.
  • Explain every violation. Show the rule, the file and line, the data-flow summary and a fix example in the file's language.
  • Group duplicates. One tainted input reaching five sinks is one problem, not five comments.
  • Make exceptions governed, not informal. An override should carry a reason and an expiry.
  • Offer the fix. Every eligible finding that gets a validated fix is one less exception request.
  • Watch what merges around the gate. A check that hangs or errors can still report success. Alert on pull requests that merge without a clean evaluation.

How Heeler pairs guardrails with fixes

Heeler's PR Guardrails gate a pull request on what the branch introduces, compared against the default-branch baseline, with Observe, Warn and Block actions and a standard scope model. SAST guardrails match new code findings by severity, confidence, category and rule, and render each finding inline on the pull request with its data-flow summary, suggested fix and CWE and OWASP references.

When a guardrail blocks on an eligible dependency vulnerability or SAST finding, Heeler can generate the fix on the pull request's own branch. The guardrail summary reports how many matched findings are auto-fixable, and each qualifying violation carries an Auto-Fixable marker. On GitHub the fix arrives as an Apply suggestion block or a Fix w/Heeler check action. On other platforms it is committed to the branch. When the target branch forbids direct pushes, Heeler opens a pull request carrying the fix. The agent stays inside the module that triggered the violation, batches eligible violations into one commit where it can, and runs one auto-fix per pull request at a time.

If build validation fails, the agent does not push a broken change. It comments on the pull request, the violation stays active and the fix is routed to manual review. Because the fix is launched from the pull request itself, it follows your source-control permissions rather than a Heeler role. The details are in Guardrail Auto-Fix and SAST Guardrails. For findings already on the default branch, the same fix generation runs from the findings list through SAST Auto-fix.

FAQ

What is a PR security gate?

A PR security gate is a check that evaluates a pull request for security issues before it merges and can pass, warn or block it. It typically covers new code weaknesses, dependencies, secrets and misconfigurations.

Should a PR security gate block or warn?

Start in observe mode, move to warn, then block once you trust the false-positive rate. Block first on the services and branches where a bad merge costs the most.

Can a blocked pull request be fixed automatically?

Yes, when the finding has a predictable, validated fix, such as a direct dependency upgrade or a high-confidence code fix. Findings without one should go to manual review with guidance.

Does auto-fixing a pull request bypass branch protection?

It should not. When a branch forbids direct pushes, the fix should arrive as its own pull request so it goes through the same review as any other change.

How do you stop a PR gate from blocking on old findings?

Compare the branch against a default-branch baseline, so only findings the change introduces can fire.

See block-and-fix on your pull requests

A gate that blocks and then hands over a validated fix is a gate engineering keeps turned on. See how Heeler gates pull requests on new findings and resolves the eligible ones on the same pull request. Get a demo.

What’s new on Heeler
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Related resources

See All Resources