GitHub User Initial Access to Private Repo


Description

Detects when a user initially accesses a private organization repository.

Query · python

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"))
Raw source GitHub User Initial Access to Private Repo · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
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"))

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.