eyeprolog

Vulnerability impact

Which services are exposed to a vulnerable library?

A vulnerability in a deeply nested dependency can expose services that never mention it directly. This example follows dependency chains from services to packages, flags high-severity vulnerabilities, and recommends urgent patches for critical services.

Run it in the playground · Source


The question

OpenSSL has a critical vulnerability. Which of our three services are affected, how serious is it, and what should be patched first?

A CVE is a published vulnerability identifier. Its CVSS score, from 0 to 10, rates the severity. Here anything above 7.0 counts as high.


The facts

depends_on(webapp, api).
depends_on(worker, queue).
depends_on(frontend, ui).
depends_on(api, auth).
depends_on(auth, openssl).
depends_on(queue, openssl).
depends_on(ui, css).

vulnerability(openssl, cve_2026_0001).
cvss(cve_2026_0001, 9.8).
fixed_by(cve_2026_0001, openssl_3_0_14).

webapp reaches OpenSSL in three hops, worker in two. frontend only reaches css, which has a lower-severity issue (5.4).


The rules

exposed_to(Service, Vulnerability) :-
  uses(Service, Package),
  vulnerability(Package, Vulnerability),
  cvss(Vulnerability, Score),
  (Score > 7.0).

urgent_patch(Service, Patch) :-
  critical(Service),
  exposed_to(Service, Vulnerability),
  fixed_by(Vulnerability, Patch).

uses/2 follows dependencies up to three hops deep, with one clause per depth. A service is exposed when it uses a package with a high-severity vulnerability; a critical exposed service gets an urgent patch.


The answer

eyeprolog examples/vulnerability-impact.pl
risk(worker, high).
risk(webapp, high).
mitigate(worker, cve_2026_0001).
mitigate(webapp, cve_2026_0001).
urgent_patch(webapp, openssl_3_0_14).
urgent_patch(worker, openssl_3_0_14).

This is the end of 20 answers; the first 14 list what each service uses and is impacted by. frontend depends on a vulnerable package too, but its CVSS score is below the threshold, so no risk is raised.


The reason

step(exposed_to(webapp, cve_2026_0001),
     rule(26),
     ['Service' = webapp, 'Vulnerability' = cve_2026_0001, 'Package' = openssl, 'Score' = 9.8],
     [uses(webapp, openssl),
      vulnerability(openssl, cve_2026_0001),
      cvss(cve_2026_0001, 9.8),
      9.8 > 7.0]).

The webapp is exposed because it uses OpenSSL, OpenSSL has CVE 2026-0001, and that CVE scores 9.8, above 7.0. The uses(webapp, openssl) step further down traces the three-hop path through api and auth.


The check

condition('C1', resolution, ok, 37).
condition('C4', coverage, ok, 64).
condition('C5', re_decision, ok, 1).
claims(20).
verdict(checked).

All 20 claims are covered. The checker replays 37 rule and fact steps and recomputes the one score comparison; nothing is trusted.


Try it

Learn more in The Art of EyeProlog, Chapter 4.