Skip to content
29 changes: 28 additions & 1 deletion example-data/testorg-unremediated.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,32 @@
"secret_scanning_push_protection_custom_link_enabled": false,
"secret_scanning_push_protection_custom_link": null,
"secret_scanning_validity_checks_enabled": false
}
},
"owners": [
{"login": "admin-user-1", "id": 1001},
{"login": "admin-user-2", "id": 1002},
{"login": "admin-user-3", "id": 1003},
{"login": "admin-user-4", "id": 1004},
{"login": "admin-user-5", "id": 1005},
{"login": "admin-user-6", "id": 1006},
{"login": "admin-user-7", "id": 1007}
],
"teams": [],
"sso": {
"enabled": false,
"enforced": false,
"sso_url": "",
"idp_issuer": ""
},
Comment thread
gusfcarvalho marked this conversation as resolved.
"default_security_configs": [
{
"default_for_new_repos": "all",
"configuration": {
"name": "Legacy Security Profile",
"secret_scanning": "disabled",
"dependabot_alerts": "not_set"
}
}
],
"ip_allow_list": []
}
30 changes: 29 additions & 1 deletion example-data/testorg.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,33 @@
"secret_scanning_push_protection_custom_link_enabled": true,
"secret_scanning_push_protection_custom_link": null,
"secret_scanning_validity_checks_enabled": true
}
},
"owners": [
{"login": "admin-user-1", "id": 1001},
{"login": "admin-user-2", "id": 1002}
],
"teams": [
{"name": "developers", "privacy": "closed", "description": "Application development team"},
{"name": "security", "privacy": "closed", "description": "Security operations team"}
],
Comment thread
gusfcarvalho marked this conversation as resolved.
Comment thread
gusfcarvalho marked this conversation as resolved.
"sso": {
"enabled": true,
"enforced": true,
"sso_url": "https://sso.example.com/saml/github",
"idp_issuer": "https://sso.example.com"
},
"default_security_configs": [
{
"default_for_new_repos": "all",
"configuration": {
"name": "Baseline Security Profile",
"secret_scanning": "enabled",
"dependabot_alerts": "enabled"
}
}
],
"ip_allow_list": [
{"allow_list_value": "203.0.113.0/24", "is_active": true, "name": "Office Network"},
{"allow_list_value": "198.51.100.0/24", "is_active": true, "name": "VPN"}
]
Comment thread
gusfcarvalho marked this conversation as resolved.
}
47 changes: 47 additions & 0 deletions policies/gh_org_admin_count.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package compliance_framework.admin_count
Comment thread
gusfcarvalho marked this conversation as resolved.
Outdated

risk_templates := [
Comment thread
gusfcarvalho marked this conversation as resolved.
Outdated
{
"name": "Excessive number of organization owners",
"title": "Too Many Organization Owners Increases Blast Radius of Privileged Account Compromise",
"statement": "Organization owners in GitHub hold the highest level of privilege: they can modify security settings, manage all members and teams, access all repositories, and permanently delete the organization. Granting owner access to more than 5 individuals significantly increases the attack surface for privilege abuse, insider threats, and account compromise scenarios. Limiting ownership to a small, well-controlled set ensures that elevated access is deliberately granted and periodically reviewed.",
"likelihood_hint": "moderate",
"impact_hint": "high",
"violation_ids": ["too_many_owners"],
"threat_refs": [
Comment thread
gusfcarvalho marked this conversation as resolved.
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-269",
"title": "Improper Privilege Management",
"url": "https://cwe.mitre.org/data/definitions/269.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-284",
"title": "Improper Access Control",
"url": "https://cwe.mitre.org/data/definitions/284.html"
}
],
"remediation": {
"title": "Reduce organization owner count to 5 or fewer",
"description": "Review the list of organization owners and remove owner access from any accounts that do not require it. Prefer using team-based admin roles for day-to-day administrative tasks, reserving full organization ownership for a minimal set of accountable individuals.",
"tasks": [
{ "title": "Navigate to Organization Settings > People > Owners" },
{ "title": "Review the business justification for each owner account" },
{ "title": "Downgrade any owners who do not require full organization-level privileges to member or team maintainer roles" },
{ "title": "Ensure remaining owners have MFA enabled and use strong authentication" },
{ "title": "Schedule a periodic review of organization ownership at least annually" }
]
}
}
]

_owners := object.get(input, "owners", [])

violation[{"id": "too_many_owners"}] if {
Comment thread
gusfcarvalho marked this conversation as resolved.
count(_owners) > 5
}

title := "Organization has 5 or fewer owners"
description := "The number of GitHub organization owners should not exceed 5 to limit the blast radius of a privileged account compromise and ensure that elevated access is deliberately granted and regularly reviewed."
remarks := "More information: https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#organization-owners"
36 changes: 36 additions & 0 deletions policies/gh_org_admin_count_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package compliance_framework.admin_count

test_admin_count_compliant if {
count(violation) == 0 with input as {
"owners": [
{"login": "admin1"},
{"login": "admin2"},
{"login": "admin3"}
]
}
}

test_admin_count_at_limit if {
count(violation) == 0 with input as {
"owners": [
{"login": "admin1"},
{"login": "admin2"},
{"login": "admin3"},
{"login": "admin4"},
{"login": "admin5"}
]
}
}

test_admin_count_exceeded if {
count(violation) > 0 with input as {
"owners": [
{"login": "admin1"},
{"login": "admin2"},
{"login": "admin3"},
{"login": "admin4"},
{"login": "admin5"},
{"login": "admin6"}
]
}
}
53 changes: 53 additions & 0 deletions policies/gh_org_default_repo_permission.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package compliance_framework.default_repo_permission

risk_templates := [
{
"name": "Default repository permission is too permissive",
"title": "Overly Permissive Default Repository Access Grants Excessive Privileges to All Members",
"statement": "The default repository permission setting determines the base access level automatically granted to every organization member on all repositories. Setting this to 'write' or 'admin' means that all organization members, including newly onboarded employees and contractors, receive write or administrative access to every repository by default. This violates the principle of least privilege and can lead to unauthorized modifications, accidental data loss, or privilege escalation if any member account is compromised. The default should be 'read' or 'none', with elevated access granted explicitly via team membership.",
"likelihood_hint": "moderate",
"impact_hint": "high",
"violation_ids": ["default_permission_too_permissive"],
"threat_refs": [
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-269",
"title": "Improper Privilege Management",
"url": "https://cwe.mitre.org/data/definitions/269.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-284",
"title": "Improper Access Control",
"url": "https://cwe.mitre.org/data/definitions/284.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-732",
"title": "Incorrect Permission Assignment for Critical Resource",
"url": "https://cwe.mitre.org/data/definitions/732.html"
}
],
"remediation": {
"title": "Set the default repository permission to 'read' or 'none'",
"description": "Configure the organization's default repository permission to 'read' or 'none'. Grant write and admin access explicitly via team membership to specific repositories, following the principle of least privilege.",
"tasks": [
{ "title": "Navigate to Organization Settings > Member privileges > Base permissions" },
{ "title": "Change the base permission to 'Read' or 'No permission'" },
{ "title": "Review all repositories to ensure teams have explicit access grants where write access is required" },
{ "title": "Communicate the change to all members and update onboarding documentation" },
{ "title": "Audit existing repositories for any direct-user write grants that should be team-based" }
]
}
}
]

_permissive_permissions := {"write", "admin"}

violation[{"id": "default_permission_too_permissive"}] if {
_permissive_permissions[input.settings.default_repository_permission]
}
Comment thread
gusfcarvalho marked this conversation as resolved.
Outdated

title := "Default repository permission is set to 'read' or 'none'"
description := "The organization's default repository permission must not grant write or admin access to all members by default. Elevated access should be granted explicitly via team membership to follow the principle of least privilege."
remarks := "More information: https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/setting-base-permissions-for-an-organization"
33 changes: 33 additions & 0 deletions policies/gh_org_default_repo_permission_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package compliance_framework.default_repo_permission

test_default_permission_read if {
count(violation) == 0 with input as {
"settings": {
"default_repository_permission": "read"
}
}
}

test_default_permission_none if {
count(violation) == 0 with input as {
"settings": {
"default_repository_permission": "none"
}
}
}

test_default_permission_write if {
count(violation) > 0 with input as {
"settings": {
"default_repository_permission": "write"
}
}
}

test_default_permission_admin if {
count(violation) > 0 with input as {
"settings": {
"default_repository_permission": "admin"
}
}
}
51 changes: 51 additions & 0 deletions policies/gh_org_ip_allowlist_enabled.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package compliance_framework.ip_allowlist_enabled

risk_templates := [
{
"name": "No IP allow-list configured for the organization",
"title": "Absence of IP Allow-List Exposes GitHub Resources to Access from Untrusted Networks",
"statement": "Without an IP allow-list, the GitHub organization's resources (repositories, API, settings) are accessible from any IP address on the internet, subject only to authentication. This means that even valid credentials used from untrusted networks (e.g., compromised endpoints, attacker infrastructure) can interact with the organization's assets. Configuring an IP allow-list restricts access to approved network ranges, adding a network-layer control that limits the blast radius of credential compromise.",
"likelihood_hint": "moderate",
"impact_hint": "high",
"violation_ids": ["ip_allowlist_not_configured"],
"threat_refs": [
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-284",
"title": "Improper Access Control",
"url": "https://cwe.mitre.org/data/definitions/284.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-923",
"title": "Improper Restriction of Communication Channel to Intended Endpoints",
"url": "https://cwe.mitre.org/data/definitions/923.html"
}
],
"remediation": {
"title": "Configure an IP allow-list for the GitHub organization",
"description": "Enable the IP allow-list feature for the organization and add the approved IP ranges from which members are permitted to access GitHub. This restricts access to known, trusted networks and reduces the risk of credential-based attacks from untrusted locations.",
"tasks": [
{ "title": "Navigate to Organization Settings > Security > IP allow list" },
{ "title": "Enable 'IP allow list'" },
{ "title": "Add approved IP ranges for corporate offices, VPNs, and CI/CD infrastructure" },
{ "title": "Test that members can still access GitHub from approved networks before fully enforcing" },
{ "title": "Document the process for requesting additions to the IP allow-list" },
{ "title": "Schedule periodic review of the IP allow-list to remove stale entries" }
]
}
}
]

_has_active_entry if {
some entry in input.ip_allow_list
entry.is_active == true
}

violation[{"id": "ip_allowlist_not_configured"}] if {
not _has_active_entry
}

title := "Organization has an active IP allow-list configured"
description := "The GitHub organization must have at least one active IP allow-list entry to restrict access to approved network ranges and reduce the risk of access from untrusted locations."
remarks := "More information: https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/managing-allowed-ip-addresses-for-your-organization"
25 changes: 25 additions & 0 deletions policies/gh_org_ip_allowlist_enabled_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package compliance_framework.ip_allowlist_enabled

test_ip_allowlist_configured if {
count(violation) == 0 with input as {
"ip_allow_list": [
{"allow_list_value": "203.0.113.0/24", "is_active": true, "name": "Office"},
{"allow_list_value": "198.51.100.0/24", "is_active": false, "name": "Old VPN"}
]
}
}

test_ip_allowlist_all_inactive if {
count(violation) > 0 with input as {
"ip_allow_list": [
{"allow_list_value": "203.0.113.0/24", "is_active": false, "name": "Disabled"},
{"allow_list_value": "198.51.100.0/24", "is_active": false, "name": "Also Disabled"}
]
}
}

test_ip_allowlist_empty if {
count(violation) > 0 with input as {
"ip_allow_list": []
}
}
Comment thread
gusfcarvalho marked this conversation as resolved.
45 changes: 45 additions & 0 deletions policies/gh_org_members_can_create_repos.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package compliance_framework.members_can_create_repos

risk_templates := [
{
"name": "Organization members can create repositories without restriction",
"title": "Unrestricted Repository Creation Undermines Access Governance",
"statement": "When all organization members are permitted to create repositories, the organization loses control over its asset inventory. Members may inadvertently expose internal code via public repositories, create repositories that bypass security baselines, or accumulate ungoverned codebases. Restricting repository creation to administrators ensures that new repositories are intentional, properly configured, and subject to security review before use.",
"likelihood_hint": "moderate",
"impact_hint": "high",
"violation_ids": ["members_can_create_repos"],
"threat_refs": [
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-284",
"title": "Improper Access Control",
"url": "https://cwe.mitre.org/data/definitions/284.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-200",
"title": "Exposure of Sensitive Information to an Unauthorized Actor",
"url": "https://cwe.mitre.org/data/definitions/200.html"
}
],
"remediation": {
"title": "Restrict repository creation to organization administrators",
"description": "Disable the ability for regular organization members to create new repositories. Only administrators should be permitted to create repositories, ensuring each new repository is intentionally provisioned and subject to organizational security baselines.",
"tasks": [
{ "title": "Navigate to Organization Settings > Member privileges" },
{ "title": "Review the Repository creation section for member repository creation settings" },
{ "title": "Disable 'Allow members to create repositories' or restrict repository creation to administrators" },
{ "title": "Review and archive any repositories created without administrative approval" },
{ "title": "Document a repository provisioning process that routes requests through an administrator" }
]
}
}
]

violation[{"id": "members_can_create_repos"}] if {
input.settings.members_can_create_repositories == true
Comment thread
gusfcarvalho marked this conversation as resolved.
Outdated
}

title := "Organization members cannot create repositories"
description := "Repository creation should be restricted to administrators to maintain control over the organization's code asset inventory and prevent ungoverned or accidentally public repositories."
remarks := "More information: https://docs.github.com/en/organizations/managing-organization-settings/restricting-repository-creation-in-your-organization"
17 changes: 17 additions & 0 deletions policies/gh_org_members_can_create_repos_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package compliance_framework.members_can_create_repos

test_members_cannot_create_repos if {
count(violation) == 0 with input as {
"settings": {
"members_can_create_repositories": false
}
}
}

test_members_can_create_repos if {
count(violation) > 0 with input as {
"settings": {
"members_can_create_repositories": true
}
}
}
Loading
Loading