Ineffective GitHub ruleset
ID |
github_rulesets |
Severity |
high |
Remediation Complexity |
moderate |
Remediation Risk |
low |
Remediation Effort |
low |
Family |
SCM |
Tags |
ASVS50:v15.1.1, branch-protection, cicd-sec-01, cicd-security, security, source-code, spvs10-v3.3.18, spvs15-v2.2.1, supply-chain |
Description
Are the GitHub rulesets protecting this repository actually effective?
Rulesets are the modern GitHub-native way to protect branches, tags and pushes. Unlike classic branch protection, a ruleset can be created, scoped and left in a state where it provides no real protection. This check inspects the repository-level and organization-level rulesets that apply to the repository and reports two weaknesses:
-
Not enforced — a ruleset that carries protection rules but whose enforcement status is
evaluate(insights only) ordisabled. It looks like protection but enforces nothing. -
Bypassable — an active ruleset that privileged actors (organization admins, teams or repository roles) can bypass unconditionally (
bypass mode = always), which defeats the control.
The presence of branch protection itself is reported by the unprotected_branch detector. This detector focuses on the quality of existing rulesets, so the two do not raise duplicate findings. Automation-only bypass actors (Integration, DeployKey) are not flagged, and pull-request-scoped bypass (bypass mode = pull_request) is treated as an accepted, weaker exception rather than an unconditional bypass.
|
Security
A ruleset only protects a ref if it is enforced and cannot be trivially circumvented.
-
Unenforced rulesets give a false sense of security: reviewers assume required reviews, signed commits or force-push protection are in place, while the ruleset is in
evaluate/disabledmode and enforces nothing. -
Unconditional bypass by privileged actors is the class of weakness behind tag- and branch-poisoning supply-chain incidents: if an organization admin, a team or a repository role can push to a protected ref or move a release tag without going through the required checks, an attacker who compromises such an identity (or a token with that role) can tamper with the code or the release artifacts despite the ruleset.
Mitigation / Fix
-
Set the enforcement status of protective rulesets to Active.
-
Remove privileged human actors (
OrganizationAdmin,Team,RepositoryRole) from the bypass list, or restrict their bypass to pull requests only. -
Keep bypass entries limited to the automation identities that genuinely need them (
Integration,DeployKey).
Follow the GitHub documentation to manage rulesets for a repository and to configure bypass permissions.
Configuration
To change these options you can modify SCANNER_DIR/conf/misconfigurations/github_rulesets.yml. The following are the default configuration properties:
# Configuration for the checks on GitHub rulesets.
properties:
# If true, report rulesets that carry protection rules but are not actively enforced
# (enforcement is 'evaluate' or 'disabled'), because they provide no real protection.
requireActiveEnforcement: true
# If true, report active rulesets that privileged actors can bypass unconditionally
# (bypass_mode = always), which defeats the control.
disallowPrivilegedBypass: true
# Actor types trusted to bypass rulesets (typically automation). Any OTHER actor type with an
# 'always' bypass is flagged. Narrow this list (e.g. to []) to also flag GitHub App / DeployKey bypass.
trustedBypassActorTypes: [ Integration, DeployKey ]