GLPI Vuln
Vulnerability and patch exposure for a GLPI 11 estate, derived from the software inventory already in GLPI. No agent, no scanner, no credentials on endpoints, no probing.

The dashboard leads with three numbers a prettier one would omit: coverage (how many machines could be examined at all), the confidence mix, and — when it is empty — which of the five reasons it is empty for.
Compared to a scanner
Section titled “Compared to a scanner”| Vulnerability scanner | This plugin | |
|---|---|---|
| Needs on the endpoint | An agent, credentials, or both | Nothing new |
| What it sees | What it can reach on the network today | Everything the inventory recorded, including machines that are off |
| Laptops off the VPN | Only if online during a scan window | Whenever they last checked in |
| Evidence of a patch | The next scan says so | The next inventory no longer shows the vulnerable version |
| What it can find | Anything probeable, including misconfiguration | Only what is in the software inventory |
| Cost to run | A scan window, a licence, an appliance | Three HTTP feeds on a cron |
A vulnerability scanner checks for open ports, weak ciphers, and service misconfigurations. This plugin checks reported package and software versions against published advisories; it complements network scanners rather than replacing them.
Confidence tiers
Section titled “Confidence tiers”Every match carries a tier, shown everywhere the match is shown. The weakest tier never becomes a finding.
| Tier | Meaning | Where it goes |
|---|---|---|
| exact | The feed asserted this version is affected — OSV matched name, ecosystem and version on its own side, or an NVD CPE names this build | Findings |
| range | The installed version was compared against a published affected range, by our comparator | Findings, badged |
| name | The product name matched but the version could not be compared | Review queue only. Never a finding, dashboard entry, ticket or tool answer |

Approving a name-level match records the mapping so future advisories for that
product match automatically by version: for example, verifying that
Acrobat Reader DC (64-bit) maps to adobe:acrobat_reader_dc.

Features
Section titled “Features”- Linux packages via OSV.dev. Package name, ecosystem and version go out in batches; OSV does the version comparison in each distribution’s own semantics. These are the most trustworthy findings the plugin produces.
- End-of-life census via endoflife.date. Which machines run something no longer receiving security updates. No CVE, no version comparison, no confidence caveat.
- Windows and macOS applications via NVD 2.0. CPE matching, which is fuzzy by construction, hence the tiers and the review queue.
- Findings close themselves. Nothing reports a patch; the next inventory shows the new version and the finding is marked patched with the date, so mean time to patch measures the estate rather than a self-report.
- Exception register. Per entity or per asset, with a named risk owner, a required reason and an expiry date. A lapsed exception brings the finding back.
- Optional remediation tickets. Off for every entity by default. One ticket per entity per advisory, under an ITIL category you choose, so remediation is SLA-measured by core.

A cycle flagged as ended with no published date says so rather than inventing one.

The register is a GLPI itemtype, so filtering, entity scoping, saved searches and CSV export are core’s.
What leaves the estate
Section titled “What leaves the estate”Product names and version strings, and nothing else. No hostname, serial, IP, entity or entity name, user, ticket, or count of anything.
- OSV.dev — package name, ecosystem name and version, in batches.
- endoflife.date — a product slug in a URL, such as
ubuntu. - NVD — no question about your estate at all; it serves modification windows of the public CVE list and matching happens locally.
Every feed is off by default and enabled individually. The settings page states this above the switches.
- No scanning. Nothing is probed, connected to, port-scanned or fingerprinted. The only outbound traffic is to the three feeds.
- No exploitation. No proof-of-concept or exploit checks. EPSS and CISA KEV enrichment are not in this cut.
- No remediation. It never patches, runs a command or touches a package manager. It opens tickets if asked.
- No re-scoring. Severity is the feed’s. Where only a CVSS 3.x vector was published the base score is computed from it; CVSS 4.0 vectors are left unscored rather than approximated.
- No configuration or compliance checks. Versions only.
Install
Section titled “Install”# from the GLPI rootgit clone https://github.com/bijstaan/glpi-vuln.git plugins/glpivulnphp bin/console plugin:install -u glpi glpivulnphp bin/console plugin:activate glpivulnPages are under Tools → Vulnerability exposure.
Settings
Section titled “Settings”Setup → Plugins → GLPI Vuln. Opens on a status card, with each feed’s real
last outcome underneath — including partial, which is the ordinary state of an
NVD backfill rather than a failure.

| Setting | Default | Notes |
|---|---|---|
| Enable GLPI Vuln | off | Master switch. Off, no feed is contacted and nothing is matched |
| OSV.dev | off | Linux package advisories |
| endoflife.date | off | Support lifecycle census |
| NVD 2.0 | off | Windows and macOS applications |
| NVD API key | — | Optional. Raises the rate from 5 requests/30s to 50. Encrypted with GLPI’s key |
| First backfill | 30 days | How far back the first NVD sync reaches. Full history is ~300,000 CVEs |
| NVD requests per run | 120 | The sync is resumable; a small budget is a slow catch-up, not a failure |
| OSV queries per run | 4000 | One per distinct package/version/ecosystem, not per machine |
| Extra EOL products | — | endoflife.date slugs beyond the operating systems already detected |
| Entities examined | allowlist, empty | An empty allowlist permits nothing |
| Ticket entities | empty | Empty means no tickets anywhere |
| Ticket severity threshold | Critical | Unrated advisories never open a ticket, at any threshold |
| ITIL category | — | Pick one your SLA rules already attach to |
| Tickets for end-of-life | off | Separate, and opened as requests rather than incidents |
| Keep patched findings | 365 days | The evidence behind every MTTP figure. 0 keeps them for ever |
Three automatic actions are registered and do nothing until the master switch is on:
| Task | Every | Does |
|---|---|---|
vulnfeeds |
12h | Refreshes enabled feeds, each inside its own guard and budget |
vulnmatch |
1h | Recomputes exposure from current inventory, closes what has been patched |
vulnworkflow |
1h | Opens and updates remediation tickets for permitted entities |
Rights
Section titled “Rights”plugin_glpivuln_exposure— dashboards, advisory pages, review queue, exception register.plugin_glpivuln_config— settings: which feeds run, the API key, what leaves the estate.
Both are granted at install to profiles holding core config UPDATE. A
service-desk lead can be given the first without the second.
glpi-ai tool
Section titled “glpi-ai tool”vuln_exposure, read-only: answers whether a computer is exposed to anything
that matters, or summarises an entity. Scoped by both the
conversation’s entity and the session’s. Every response carries the confidence
mix and the feed freshness.
Limitations
Section titled “Limitations”- The package source is inferred, not read. GLPI’s inventory format carries
a
fromfield on every software entry (deb,rpm,registry, …) and core discards it. Ecosystem is inferred from the machine’s OS; a machine with no OS recorded contributes no Linux packages, and the dashboard reports how many rather than counting them clean. - Not every distribution is covered. OSV has no ecosystem for CentOS, Fedora, Oracle Linux, Amazon Linux, Arch or Linux Mint. Those machines are counted as unmapped on the settings page.
- The version comparator is pragmatic. dpkg and rpm ordering are faithful; Ubuntu ESM suffixes are not understood and there is no pacman scheme. OSV findings do not depend on it.
- CPE matching over-matches by construction. NVD’s configuration trees
express “this application running on that OS” and GLPI does not record
running-on relationships, so the tree is flattened. This is why an NVD match
is never better than
range. - CVSS 4.0 is not scored. Its score needs a 270-entry lookup table plus an interpolation procedure; a partial implementation would produce numbers that look right and are not. A 4.0-only advisory keeps its feed-supplied label or shows as unrated.
- MTTP has a blind spot. A machine that stops being inventoried looks like one that was patched. Those are excluded and counted separately as “went quiet”.
- The first MTTP cycle is meaningless. Exposure clocks start when the plugin first sees a finding, not at CVE publication. No figure is shown until ten findings have closed.
docker compose -p glpi exec glpi sh -c 'cd /var/www/glpi/plugins/glpivuln && tests/run.sh'Five suites, none needing a database: the version comparator, the CPE scorer and
CVSS arithmetic, the three feed parsers against captured fixtures, the EOL and
ecosystem mapping, and the transport layer against a mock feed server that
run.sh starts itself.
tests/matching.php covers the state machine — dismissals surviving a re-sync,
a finding closing itself, a regression starting a new clock, an exception
suppressing and then lapsing — and needs a live instance with the plugin
installed:
docker compose -p glpi exec glpi \ php /var/www/glpi/plugins/glpivuln/tests/matching.phpIt writes only rows prefixed ZZTEST-, removes them on the way out, and
snapshots and restores the settings it touches through raw glpi_configs rows.
tests/browser/vuln-check.js checks the pages in a real browser and takes the
screenshots above.
Licence
Section titled “Licence”GPL-3.0-or-later, the same licence as GLPI. The plugin is loaded into GLPI’s process and extends its classes, so it is a derivative work. See LICENSE.