Dev & EngARTICLE

GitHub now blocks pull request merges with exposed secrets

A new repository ruleset rule blocks the merge when secret scanning finds a credential in the PR's commits. It complements push protection, but doesn't replace it.

GitHub now blocks pull request merges with exposed secrets
Image: Bisneto Braga

GitHub announced in the September 9, 2026 changelog a new repository ruleset rule that blocks the merge of a pull request when secret scanning detects credentials introduced by that PR's commits. In practice, a secret leak stops being something discovered later (with the commit already on the protected branch) and becomes a block in the review flow, at the exact point where the team decides to integrate the code.

The rule is called require_secret_scanning_alert_resolution (that's the name in the REST API; in GraphQL, REQUIRE_SECRET_SCANNING_ALERT_RESOLUTION) and is in public preview for those with GitHub Secret Protection or GitHub Advanced Security. In other words: it's not a free feature for any repository, it's part of GitHub's paid security layer.

What the rule checks before allowing the merge

According to the changelog, the rule validates two conditions before allowing a PR to be merged:

  1. A secret scan has completed for the PR's top commit (head commit).
  2. No alert is open for secrets introduced by that PR's commits.

The detail that matters here is scope: the rule looks at secrets introduced by the PR itself, not at everything that was already rotten in the repository. It's a sensible design decision, because it avoids punishing a new PR for a credential someone committed two years ago that nobody resolved. The block stays focused on what that specific change brought that's new.

By default, the rule runs on open PRs and blocks secrets detected by provider patterns, the patterns GitHub maintains for known credentials (AWS keys, Stripe tokens, etc.). Optionally, it can be expanded to other categories, such as custom patterns (the patterns the organization itself defines) or generic patterns (the heuristic that tries to catch generic secrets that don't match any known format).

Anyone without bypass permission can only unlock the merge by resolving each alert, which in practice means removing the secret from the history and rotating the exposed credential.

Why this isn't the same as push protection

This is the part worth understanding well, because the two things seem redundant and they aren't. The changelog itself makes the distinction:

Push protection stops a secret at the push, before it ever reaches the repository. This rule adds an additional layer of protection at the pull request layer.

>

-- GitHub Changelog

Push protection acts at git push: it intercepts the secret before it ever reaches the repository. It's the earliest possible barrier, and the most effective one, because the credential is never persisted on the server.

The new rule acts one layer later, at merge time. It exists precisely to catch the cases push protection didn't catch or wasn't configured to catch. The example GitHub gives is the most realistic scenario of all: a team can keep push protection turned off for generic pattern secrets (which frequently generate false positives and would block legitimate pushes), but still keep a ruleset that blocks the merge of those same secret types. You trade the friction of the push (which hits the individual dev, all the time) for the friction of the merge (which happens once, with the reviewer nearby).

In summary, the two tools solve the same problem at different points in the code's lifecycle:

| | Push protection | Ruleset rule (new) | |---|---|---| | Where it acts | At git push | At PR merge | | Does the secret reach the repo? | No | Yes (stays in the PR branch until resolved) | | Who feels the friction | The dev, every push | The PR, once, at merge | | Good for | Provider patterns | Cases push protection doesn't cover |

The way I read it: they don't compete, they stack. Push protection is the first line; the merge rule is the safety net for what slipped underneath it.

How to configure it

The path through the interface is the same as any ruleset. In the repository, organization, or enterprise settings, go to Repository > Rulesets, create or edit a ruleset targeting the branches you want to protect, and check Require secret scanning alerts are resolved.

For those who prefer to manage this as code (the path I'd follow in any org with more than a handful of repositories), you can use the REST API with the rule type require_secret_scanning_alert_resolution and a secret_types parameter to control which categories are included in the block. A conceptual excerpt of a ruleset with this rule looks like this:

json
{
  "type": "require_secret_scanning_alert_resolution",
  "parameters": {
    "secret_types": ["provider", "custom", "generic"]
  }
}

Managing rulesets via API is what makes this protection scalable: you apply the same policy to hundreds of repositories at once, at the organization or enterprise level, instead of relying on each team remembering to flip the switch. That, incidentally, is the central point of rulesets ever since they replaced the old branch protection rules.

What changes in practice (and where it doesn't solve anything)

For the Brazilian team that treats the PR as the quality gate before production, this rule closes a concrete gap: until now, secret scanning warned you about the leak, but didn't block the merge by itself. You depended on a manually configured required check or on the reviewer's discipline. Now the block is native to the ruleset, in the same place where you already require status checks, approvals, and linear history.

But it's worth being honest about the limits, because none of these tools is a silver bullet:

  • The secret has already leaked. If push protection was turned off, the credential is already in the PR branch and in the Git history. Blocking the merge doesn't un-leak anything. Resolving the alert necessarily means rotating the credential and cleaning up the history. A secret that was exposed on a public branch for a few hours must be considered compromised, period.
  • It's paid. Without Secret Protection or Advanced Security, this rule doesn't exist for you. Teams on the free plan still depend on basic secret scanning and process discipline.
  • Bypass is a double-edged sword. Whoever has bypass permission can get around the block. Used well, it's the escape hatch for emergencies; poorly governed, it becomes the hole everyone slips through. It's worth auditing who has that power.
  • It's in public preview. Behavior and naming may change before GA, so treat it as something to test on non-critical repositories first.

GitHub points to the secret scanning and push protection documentation and the rulesets documentation for enforcement and bypass details. For those already living inside the Advanced Security ecosystem, turning on this rule in an organization ruleset is an easy win. For those without it, the indirect message is the usual one: the safest secret is the one that was never committed, and that remains a process problem (environment variables, secret managers, a well-made .gitignore), not just a tooling one.

Translated from the Brazilian Portuguese original · Read the original