Release-asset binaries

Check G9 · provenance family · severity HIGH · automatic · one of the 22 GitLab checks

The question this check asks: are the files attached to this project's releases executable programs or archives — .zip, .exe, .dll, .jar, .dmg, .msi — rather than source? On gitlab.com a release asset is a link: a name and a URL that may point at the project's package registry or at another host altogether.

Why it matters

Source review and most code scanning look at the project's files. A payload attached to a release is never in those files. On GitHub that is the whole FakeGit story of 2026 — 211 repositories, 335 assets, 14,084,688 downloads, every one through a browser's download button — and it is the reason RepoGates exists; the FakeGit intelligence page has it in full.

On gitlab.com the record is different, and this page says so plainly: no campaign of that shape — no typosquat, fake-maintainer or trojanised-release-asset campaign specific to gitlab.com — was found for 2024–2026, so there is no catch rate to publish for this check here, and GitHub's numbers are not transferred. What GitLab's own threat intelligence reported (19 February 2026) is a clone-and-run pattern: 131 accounts banned in 2025 for North Korean nation-state malware distribution, and in more than 80% of instances the payload was not stored on gitlab.com at all — the project held a concealed loader that fetched it from elsewhere, most commonly Vercel. Cofense (8 April 2026) put the split of the phishing campaigns it studied at 95% abusing GitHub to 5% abusing GitLab. The check keeps its weight regardless, because the mechanism is a property of releases, not of a host, and a tool project whose value lives in a downloadable program deserves the same default suspicion on either. The GitLab intelligence page has the record.

How RepoGates scores it

G9 is the same check as C9, run by the same code on a snapshot built from gitlab.com's releases API, which a public project answers anonymously. Each release's assets.links[] becomes an asset, named by the link's name (or the last segment of its URL when the name is empty). Two things GitHub publishes are missing here: gitlab.com publishes no download counts, so every asset carries 0, and the source archives it generates for every tag — assets.sources[], in zip, tar.gz, tar.bz2 and tar — are not assets and never fire.

The check fires when an asset name ends in one of the extensions above. It costs 10 points at severity HIGH, so a project that trips nothing else scores 90 and reads REVIEW. One shape is graded lower: a .tar.gz or .zip whose name matches a wheel beside it — flask-3.1.3.tar.gz next to flask-3.1.3-py3-none-any.whl — is a Python source distribution, the ordinary Python release shape, and costs 5 points at MEDIUM, named as such. An archive with no wheel to vouch for it stays HIGH. It never blocks a download on its own — the evidence note in the scoring table says why:

“the FakeGit delivery path, but 95% of legit binary-shipping tools fire it — moderate weight, panel explains”

Combined with a young owner account, a project created days ago or inorganic stars, the same asset is part of a BLOCK — with one GitLab caveat: a group's age is read anonymously, a user namespace's only with a token, so on a user-owned project the owner-age half of that combination may be listed as not checked. Measured on 19 September 2026 across the 100 most-starred gitlab.com projects, this check fired on 10 (62 of the 100 publish releases at all) and was the sole reason for a REVIEW once; GitHub's 100 most-starred, read the same day by the same engine, fired it 27 times.

False positives we know about

Almost every legitimate desktop tool, CLI, game mod and firmware project ships a binary release. In the Phase 0 measurement on GitHub controls, 95% of the legitimate binary-shipping repositories fired this check, and gitlab.com is no different in kind: fdroid/fdroidclient, which ships its releases as binaries, read REVIEW with this row beside a submodule file and a build wrapper. That is why it warns, and why the board names the asset rather than just the verdict: you can see which file it is talking about.

What this check does not cover

It sees release assets by name. It does not open them, does not scan them, and does not see what a binary does when run. It also does not see where a link resolves: on gitlab.com the address a browser follows — /-/releases/<tag>/downloads/<file> — answers a 302 to the link's own URL, which is free text. Measured live, glab's .deb came back from the project's generic package registry, 17,517,258 bytes; another project's link may point at a host that is not gitlab.com at all. The finding names the asset, not its destination, and a browser gate on that download needs the initiating URL — one reason the board on gitlab.com pages is a later release. A deep scan reads the project's files in a sandbox; it does not execute release assets either.

RepoGates runs the same 22 checks on a gitlab.com project that it runs on a GitHub repository, from gitlab.com's public API, under the key gl/{namespace…}/{project}. What that API withholds from an anonymous caller — fork status, a user namespace's account age, and OpenSSF Scorecard, which does not cover gitlab.com — is listed as not checked, never assumed. A self-managed GitLab is another hostname and is not assessed. The repository's code is not read on this tier: a PASS means the provenance and the declared execution surface are clean.

Check it yourself

Without installing anything: open the project's Releases page and read the asset names under the latest release — and, on gitlab.com, the address each one points at. From a terminal, with every / in the project path written as %2F:

curl -s "https://gitlab.com/api/v4/projects/NAMESPACE%2FPROJECT/releases?per_page=1" | jq '.[0].assets | {links: [.links[] | {name, link_type, url}], sources: [.sources[].format]}'

The sources are gitlab.com's own archives of the tag and are not what this check reads; the links are. Then compare the release's tag against the commit history. A release whose assets appeared without a corresponding change in the source is the pattern FakeGit used, and it is not a GitHub-only trick.

Questions

Does a binary release asset mean the project is malicious? No. About 95% of legitimate tools that ship a program fired this check on GitHub controls, and 10 of the 100 most-starred gitlab.com projects fire it today. It is one signal among 22, scored as a warning, and it never blocks on its own.

Why do release assets matter more than the source tree? Because a payload in a release archive is never seen by source review or by most code scanning. That is where FakeGit put it on GitHub. On gitlab.com no campaign of that shape is in the record — the documented pattern there is a loader in the project that fetches its payload from another host — but the mechanism belongs to releases, not to a host, and the check keeps its weight.

Does RepoGates stop git clone of a gitlab.com project? No. RepoGates does not see git clone, glab, package managers or curl run from a terminal, and the extension's board on gitlab.com pages is a later release. What reads a gitlab.com project today is the verdict API, the MCP server and the RepoGates plugin's hook on Claude Code's Bash tool, which sends a git clone https://gitlab.com/… or glab repo clone command line to preflight before it runs and answers on this check's dimension — a refusal or a question for that one tool call, not a wall around git.

Related checks

C9 Release-asset binaries — the GitHub original · G15 Committed binaries — binaries inside the source tree rather than attached to a release · G16 Install scripts — a script that fetches and runs something, the shape GitLab's own threat intelligence describes · G1 Owner account age — the finding that turns this warning into a block, when the namespace lets it be read.

Add RepoGates to Chrome Pricing

Numbers on this page: the FakeGit campaign as published on the GitHub intelligence page; GitLab Threat Intelligence, 19 February 2026, and Cofense, 8 April 2026, as published; the releases API as read live on 18 September 2026; the 100 most-starred gitlab.com projects and GitHub's 100 as the control, read on 19 September 2026. Check numbering follows the product's catalogue.