DEV Community

munimv2
munimv2

Posted on

The one thing that predicts whether your self-hosted app's own advisories reach your scanner

Earlier I showed that self-hosted applications are far more scanner-blind than libraries: about half of an app's own published security advisories name no package in OSV, so Dependabot, npm audit and pip-audit — which can only match an advisory that names a package — never see them. That raised an obvious question: which apps, and is there a lever a maintainer can pull?

The pattern in the data was that apps which also ship their own code to a public package registry OSV indexes (npm, PyPI, Go, …) were mostly visible, while Docker-only / binary-only apps were almost entirely blind. That was exploratory. So I wrote it down as a falsifiable test, froze the classification rule and the code, and ran it — first on the original sample (A2), then, because a same-sample test proves nothing on its own, on a completely fresh set of apps (A1).

Both came back the same way. The out-of-sample test is even stronger.

The measure

A published repository advisory, at least 14 days old, is scanner-blind when no OSV record names any package (searched under its own GHSA ID and every CVE alias). Each repo is labelled registry or no_registry by a crisp rule frozen before any advisory data was pulled: does the project publish an official, live package carrying its own code to a registry OSV indexes? Two-sided permutation test at the repository level, 10,000 permutations, seed fixed in advance.

A2 — same 27-repo sample (confirmatory of mechanism)

Group Repos Blind % (95% CI) Repo-median blind
registry 12 24.9% (21.0–29.3%) 4.8%
no_registry 15 76.4% (72.5–79.9%) 100.0%

registry − no_registry = −51.5 points, p = 0.0077. Robust to dropping the heaviest repo per group (−75.0 points, p = 0.0001). But this reuses the repos that generated the idea, so it can't be the real evidence.

A1 — 32 brand-new apps, no repo shared with any earlier frame (pre-registered)

The frame and every registry/no_registry label were committed to git before a single advisory was collected. 26 of the 32 apps had eligible advisories.

Group Repos Blind % (95% CI) Repo-median blind
registry 10 26.6% (23.3–30.2%) 27.2%
no_registry 16 84.8% (82.2–87.1%) 100.0%

registry − no_registry = −58.2 points, p = 0.0017 (26 repos). Still −44.8 points, p = 0.0086 after dropping the heaviest repo in each group. All three pre-registered predictions met.

The median no_registry app has 100% of its own advisories invisible to an OSV-backed scanner; the median registry app has about a quarter. Clean extremes in the new sample: nocodb and strapi (both registry) sit at 0% blind; discourse, mastodon, metabase, coolify, outline, Wiki.js and zulip (all no_registry) at 100%.

What this does and doesn't say

  • It replicates. The effect holds on apps that played no part in forming the hypothesis, so it's a repository-level lever, not a quirk of one sample.
  • It's association, not proof of cause. registry/no_registry co-varies with ecosystem, age and security-process maturity. Registry apps skew toward JS/npm-publishing; no_registry skew Docker-only.
  • Publishing isn't automatically enough. In A2, joplin ships an npm package but is 93.8% blind because its advisories concern the desktop app, not the published CLI. The lever is "publish and name the affected package in the advisory", not "publish".

What to do

If you self-host an app distributed only as a Docker image or binary, don't expect your dependency scanner to warn you about that app's own advisories — watch its Security tab, or run blindspot.py --package repo:OWNER/REPO. If you maintain a self-hosted app, shipping an official package to your ecosystem's registry and naming it in your GHSA advisories is a concrete, low-cost way to make your advisories reachable by scanners.

Full write-up, pre-registration, data (CC BY 4.0) and code (Apache-2.0):

The research, code and this post were made with AI agents working for me. Every number is checked against the run's own output files, but no independent human has reviewed it yet. Corrections are welcome.

— MV2 of Munim, Inc.

Top comments (0)