AnalysisType: rule
Filename: github_repo_initial_access.py
RuleID: "GitHub.Repo.InitialAccess"
DisplayName: "GitHub User Initial Access to Private Repo"
Enabled: true
LogTypes:
- GitHub.Audit
Tags:
- GitHub
Reference: https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/managing-an-individuals-access-to-an-organization-repository
Severity: Info
Description: Detects when a user initially accesses a private organization repository.
Tests:
- Name: GitHub - Initial Access
ExpectedResult: true
Mocks:
- objectName: get_string_set
returnValue: ""
- objectName: put_string_set
returnValue: ""
Log:
{
"@timestamp": 1623971719091,
"business": "",
"org": "my-org",
"repo": "my-org/my-repo",
"action": "git.push",
"p_log_type": "GitHub.Audit",
"protocol_name": "ssh",
"repository": "my-org/my-repo",
"repository_public": false,
"actor": "cat",
"user": "",
}
- Name: GitHub - Repeated Access
ExpectedResult: false
Mocks:
- objectName: get_string_set
returnValue: >
"cat":"my-repo"
Log:
{
"@timestamp": 1623971719091,
"business": "",
"org": "my-org",
"repo": "my-org/my-repo",
"action": "git.push",
"p_log_type": "GitHub.Audit",
"protocol_name": "ssh",
"repository": "my-org/my-repo",
"repository_public": false,
"actor": "cat",
"user": "",
}
- Name: GitHub - Initial Access Public Repo
ExpectedResult: false
Mocks:
- objectName: get_string_set
returnValue: ""
- objectName: put_string_set
returnValue: ""
Log:
{
"@timestamp": 1623971719091,
"business": "",
"org": "my-org",
"repo": "my-org/my-repo",
"action": "git.push",
"p_log_type": "GitHub.Audit",
"protocol_name": "ssh",
"repository": "my-org/my-repo",
"repository_public": true,
"actor": "cat",
"user": "",
}
- Name: GitHub - Clone without Actor
ExpectedResult: false
Log:
{
"@timestamp": 1623971719091,
"business": "",
"org": "my-org",
"repo": "my-org/my-repo",
"action": "git.push",
"p_log_type": "GitHub.Audit",
"protocol_name": "ssh",
"repository": "my-org/my-repo",
"repository_public": false,
"actor": "",
"user": "",
}
- Name: GitHub - Initial Access by Allowed User
ExpectedResult: false
Mocks:
- objectName: get_string_set
returnValue: ""
- objectName: put_string_set
returnValue: ""
Log:
{
"@timestamp": 1623971719091,
"business": "",
"org": "my-org",
"repo": "my-org/my-repo",
"action": "git.push",
"p_log_type": "GitHub.Audit",
"protocol_name": "ssh",
"repository": "my-org/my-repo",
"repository_public": false,
"actor": "secret-scanning[bot]",
"user": "",
}
# ------ paired body: github_repo_initial_access.py ------
from panther_detection_helpers.caching import get_string_set, put_string_set
CODE_ACCESS_ACTIONS = [
"git.clone",
"git.push",
"git.fetch",
]
def rule(event):
# if the actor field is empty, short circuit the rule
# Excluding secret scanning bots
allowed_users = ["secret-scanning[bot]"]
actor = event.udm("actor_user")
if not actor or any(allowed_user in actor for allowed_user in allowed_users):
return False
if event.get("action") in CODE_ACCESS_ACTIONS and not event.get("repository_public"):
# Compute unique entry for this user + repo
key = get_key(event)
previous_access = get_string_set(key)
if not previous_access:
put_string_set(key, key)
return True
return False
def title(event):
return (
f"A user [{event.udm('actor_user')}] accessed a private repository "
f"[{event.get('repo', '<UNKNOWN_REPO>')}] for the first time."
)
def get_key(event):
return __name__ + ":" + str(event.udm("actor_user")) + ":" + str(event.get("repo"))