LoFP LoFP / developers downloading archives for offline review, backup jobs, or ci that fetches zipballs. confirm the actor, token type, and whether the repositories are expected.

Techniques

Sample rules

GitHub Exfiltration via High Number of Repository ZIP Downloads

Description

Detects a high number of GitHub repository ZIP archive downloads by a single non-bot user from one source IP within a short window. The repo.download_zip action retrieves a full repository archive over HTTP, so adversaries use it to collect source code without a git clone (which clone-threshold rules watch), including with classic PATs, fine-grained PATs, or OAuth tokens. Grouping by actor and source IP and requiring a high archive-download count separates bulk source collection from occasional developer downloads.

Detection logic

from logs-github.audit-* metadata _id, _index, _version
| where
  data_stream.dataset == "github.audit" and event.action == "repo.download_zip" and
  github.actor_ip is not null and github.actor_is_bot == false
| stats
  Esql.event_count = COUNT(*),
  Esql.github_repo_unique_count = COUNT_DISTINCT(github.repo),
  Esql.github_org_values = VALUES(github.org),
  Esql.github_repo_values = VALUES(github.repo),
  Esql.github_programmatic_access_type_values = VALUES(github.programmatic_access_type),
  Esql.github_user_agent_values = VALUES(github.user_agent),
  Esql.agent_id_values = VALUES(agent.id),
  Esql.data_stream_dataset_values = VALUES(data_stream.dataset),
  Esql.data_stream_namespace_values = VALUES(data_stream.namespace),
  Esql.github_token_id_values = VALUES(github.token_id)
  by user.name, github.actor_ip, Esql.time_window = DATE_TRUNC(10 minutes, @timestamp)
| keep user.name, github.actor_ip, Esql.*
| where Esql.event_count >= 8