Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/morwn/github-threat-detector/llms.txt

Use this file to discover all available pages before exploring further.

Release tampering is one of the highest-impact supply chain attacks because it affects every downstream user who installs or updates the package. An attacker who gains momentary write access to a repository — through a compromised token, social engineering, or a dependency confusion attack on the release tooling itself — can publish a malicious release without any prior visible activity in the repository. The two rules in this category address that scenario directly: the first fires when a release is published by an actor with no verifiable history in the repository, and the second fires when releases are created at a machine-like rate that suggests automated hijack tooling.

release-actor-anomaly

Severity: critical
Required data: Events + releases (--releases) + contributors (--contributors, optional but recommended)

What it detects

A ReleaseEvent where the publishing actor:
  1. Has no prior push history in the repository (not found in github_events for PushEvent), and
  2. Is not in the contributor list (not found in repo_contributors), and
  3. Has published fewer than 2 total releases in this repository.
Bot accounts — those whose login ends with -bot or contains [bot] — are explicitly excluded, as they are legitimate release automation and never appear in push history.

How detection works

The analyzer builds a known_actors CTE by unioning all actors who have ever pushed to the repository with all entries in the repo_contributors table (populated by --contributors). It then queries for non-bot release events where the actor does not appear in that known set and has a total release count below 2.
WITH known_actors AS (
    SELECT DISTINCT repo_name, actor_login
    FROM github_events
    WHERE event_type = 'PushEvent'
    UNION
    SELECT repo_name, actor_login
    FROM repo_contributors
),
release_counts AS (
    SELECT repo_name, actor_login, COUNT(*) AS total_releases
    FROM github_events
    WHERE event_type = 'ReleaseEvent'
    GROUP BY repo_name, actor_login
)
SELECT r.*
FROM releases r
LEFT JOIN known_actors ka
  ON r.repo_name = ka.repo_name AND r.actor_login = ka.actor_login
JOIN release_counts rc
  ON r.repo_name = rc.repo_name AND r.actor_login = rc.actor_login
WHERE ka.actor_login IS NULL
  AND rc.total_releases < 2
The total_releases < 2 guard prevents a scenario where a new-but-legitimate maintainer’s first release triggers a flood of findings once they’ve established a pattern.

Finding description

Release published by <actor_login> who has no prior push history in this repo

Evidence fields

FieldDescription
tag_nameThe release tag (e.g. v1.4.2)
release_nameThe human-readable release title
created_atTimestamp when the release was published
A release published by an actor with no prior history is a critical signal. Attackers who hijack a repository via a stolen token frequently publish exactly one release before the token is revoked. The combination of “unknown actor” and “first-ever release” is a high-confidence indicator.Remediation: Immediately audit the release artifacts — checksums, binary contents, and the release workflow logs. Yank the release if anything is suspicious and rotate all tokens that had write access at that time.

Improving accuracy with --contributors

Without --contributors, the known_actors set only contains actors who have made direct pushes recorded in the events table. If a contributor has only submitted merged pull requests (which appear as push events from the merge bot, not the contributor), they will not be in the push history and could generate a false positive. Seeding the contributor list with --contributors adds all repository contributors recognized by the GitHub API, eliminating this class of false positive:
github-threat-detector collect --repo owner/repo --releases --contributors

rapid-releases

Severity: high
Required data: Releases (--releases)

What it detects

An actor who publishes 3 or more releases within a single clock hour, and for whom this is the first time this burst pattern has occurred. Bot accounts are excluded.

How detection works

The analyzer groups release events by actor, repository, and hour bucket (date_trunc('hour', created_at)). Any actor-hour bucket with 3 or more events is a candidate. A second aggregation counts how many such rapid-window buckets the actor has historically produced. Only actors with exactly one rapid window (i.e. this is their first burst) generate a finding, which prevents noisy alerts for repositories that legitimately use automated release tools.
WITH rapid_windows AS (
    SELECT actor_login, repo_name,
           date_trunc('hour', created_at) AS hour_bucket,
           COUNT(*) AS cnt
    FROM github_events
    WHERE event_type = 'ReleaseEvent'
      AND actor_login NOT LIKE '%-bot'
      AND actor_login NOT LIKE '%[bot]'
    GROUP BY actor_login, repo_name, date_trunc('hour', created_at)
    HAVING COUNT(*) >= 3
),
baseline AS (
    SELECT actor_login, repo_name, COUNT(*) AS prior_windows
    FROM rapid_windows
    GROUP BY actor_login, repo_name
)
SELECT rw.*
FROM rapid_windows rw
JOIN baseline b USING (actor_login, repo_name)
WHERE b.prior_windows = 1

Finding description

Actor <actor_login> published <count> releases within one hour

Evidence fields

FieldDescription
countNumber of releases published in the hour window
first_atTimestamp of the first release in the burst
last_atTimestamp of the last release in the burst
A first-time burst of 3+ releases is unusual for human actors but common in automated release hijack scenarios. If the actor is a known maintainer who is doing a legitimate multi-package release, you can suppress the finding by adding them to the allow-list in your configuration.If the actor is unfamiliar, cross-reference with release-actor-anomaly findings for the same actor and time window.

Build docs developers (and LLMs) love