Techniques
Sample rules
GitHub API Sensitive Resource Enumeration
- source: elastic
- technicques:
- T1213
- T1526
- T1552
Description
Detects a burst of GitHub api.request events from a single non-bot actor and source IP against sensitive routes such
as Actions/Dependabot/environment secrets, public keys, git trees and contents, zipball archives, organization
repository and member lists, webhooks, installations, and personal access tokens. Grouping by actor and source IP and
requiring a high request count spread across several distinct sensitive routes separates broad enumeration from a
single high-volume endpoint. This pattern is commonly used for credential discovery and source collection after token
theft. Requires GitHub Enterprise audit log streaming with API Request Events enabled.
Detection logic
from logs-github.audit-* metadata _id, _index, _version
| where
data_stream.dataset == "github.audit" and event.action == "api.request" and
github.actor_ip is not null and (github.actor_is_bot is not null and github.actor_is_bot == false) and
(
github.route like "*secrets*" or
github.route like "*public-key*" or
github.route like "*git/trees*" or
github.route like "*contents*" or
github.route like "*zipball*" or
github.route like "*hooks*" or
github.route like "*installations*" or
github.route like "*members*" or
github.route like "*outside_collaborators*" or
github.route like "*personal-access-token*" or
github.route == "/organizations/:organization_id/repos"
)
| stats
Esql.event_count = COUNT(*),
Esql.github_route_unique_count = COUNT_DISTINCT(github.route),
Esql.github_repo_unique_count = COUNT_DISTINCT(github.repo),
Esql.github_route_values = VALUES(github.route),
Esql.github_org_values = VALUES(github.org),
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 >= 15 and Esql.github_route_unique_count >= 3