# 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](https://eyereasoner.github.io/eyeprolog/playground#example=vulnerability-impact) ·
[Source](../vulnerability-impact.pl)

---

# 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

```prolog
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

```prolog
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

```sh
eyeprolog examples/vulnerability-impact.pl
```

```text
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

```text
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

```text
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

- Add `depends_on(css, openssl).` and predict which new risks appear.
- Make the dependency chain four hops deep. Which answer disappears, and how
  would a recursive `uses/2` fix it?
- Lower the threshold to 5.0 and predict the frontend's risk.

Learn more in [*The Art of EyeProlog*](https://eyereasoner.github.io/eyeprolog/the-art-of-eyeprolog),
Chapter 4.
