DEV Community

Cover image for octoscope 0.27.0 — a scan that notices, not just describes
Giovambattista Fazioli
Giovambattista Fazioli

Posted on

octoscope 0.27.0 — a scan that notices, not just describes

There is a question a security tool ought to be able to answer, and octoscope's could not: did something change?

The supply-chain scan has been able to describe a repository since 0.20.0 — here is what auto-executes, here is a commit tip that looks forged. That catches an implant you happen to scan while it is sitting there. It is no help at all with the two questions you actually have when something is going around: did anything move, and what could whoever got in reach?

This release answers both.

Octoscope

What changed since the last scan

Every scan now quietly records a fingerprint of what auto-executes in the repository. The next one diffs against it and tells you what moved: a file that auto-executes appeared, an existing one's contents changed, a branch tip that used to be signed no longer is.

What makes this the most durable check in the whole scan is that it cares about neither the filename nor the contents. A variant that renames its dropper and obfuscates it differently walks straight past every content check — but it still has to appear, and appearing is the thing being watched.

Three decisions around it that I think matter more than the feature itself:

The first scan of a repository says so out loud. There is no baseline yet, so there is nothing to compare against — and staying quiet there would be indistinguishable from "nothing changed". A tool that cannot tell you the difference between I looked and it is fine and I had nothing to look at is worse than one that admits it.

A baseline older than a month still lists what changed, but stops affecting the verdict. Months of perfectly legitimate drift, scored as suspicion, would just train you to ignore the whole thing.

And files that change constantly are not tracked at allpackage.json, editor task files. Diffing those would bury any real signal under your own commits.

This is the one file octoscope writes on its own: scan-baselines.json, sitting beside your config. Deleting it is harmless — the next scan simply starts a fresh baseline.

What a compromise could reach

The second half is your capability footprint: what workflow permissions and triggers you declare, self-hosted runners, write-access deploy keys, webhooks delivering somewhere other than GitHub.

Here is the part I want to be clear about, because getting it wrong would have made the feature worthless: holding power is not a finding. octoscope's own release workflow asks for contents: write and reads two secrets, and it is completely correct — it fires on a tag push, so only someone who can already push tags can reach it. If that scored, a large share of GitHub would light up, and everyone would learn to ignore the axis within a week.

What scores is power reachable from untrusted input: a pull_request_target workflow holding the repository's secrets, or a self-hosted runner that an outsider's pull request can actually target. Both halves of that matter — a fork-triggered job running on a hosted runner, sitting beside a self-hosted runner your release workflow uses, is two unrelated facts rather than an escalation.

The checks that need admin scope fail open: a token without them still gets a complete scan of everything else. But failing open is not the same as staying quiet, so the report names what it could not look at — "deploy keys (the token lacks the scope this needs)" — and says plainly that a clean result covers only what was checked.

And a signal that sat unused for two months

There is a timing check that spots a worm fanning out: many repositories pushed within seconds of each other, the way the reference attack hit five in 49 seconds. It has been built and tested since 0.20.0 and connected to nothing, because it shipped once as an always-on banner and had to be pulled. Timing alone cannot tell a fan-out from someone scripting an update across their own repos, and without a recency gate an old batch re-alarmed forever.

Folding it into the on-demand scan fixes both objections at once. It only looks at the last hour, and it only ever adds weight to a repository that already scored on another check. A push burst by itself is a Tuesday. A push burst next to a fresh ignition point is something to go and look at.

One check is never enough

Worth saying because it constrains everything above: no single axis can reach a high verdict on its own. The capability half carries an explicit ceiling below the suspicious threshold, so even its worst possible shape lands on watch and needs a second, independent signal to agree before the verdict escalates.

That ceiling exists because a review caught the first version reaching suspicious by itself. The findings past the ceiling are still reported in full — the arithmetic is bounded, not the disclosure.

Upgrade

brew upgrade gfazioli/tap/octoscope
Enter fullscreen mode Exit fullscreen mode

Then open a repository in the Repos tab and press s. The first scan will tell you it has nothing to compare against yet, which is exactly the point — the second one won't.


Top comments (0)