Code dependency CVE relevance with LLM_SCORE

Walk transitive dependency edges and have the LLM judge if a CVE actually applies in your context

All recipes· graph· 10 minutesadvancedcypher

Code dependency CVE relevance with LLM_SCORE

Objective

Vulnerability scanners flag every transitive dependency with a published CVE. 80% of those flags are false alarms because the vulnerable code path is never reached in your application. Walk the dependency graph in Cypher, then ask LLM_SCORE "given this CVE description and how the dependency is used, is this exploitable here?" The wow moment: a single query returns the short list of CVEs that actually matter for your service, with the LLM's reasoning attached.

Step 1: Set up the dependency graph

MERGE (svc:Service {name: "Northwind API",
       description: "Public REST API for Northwind Logistics, accepts JSON, parses XML invoices, decodes JWT auth"})

// Direct dependencies
MERGE (a1:Package {name: "axum",          version: "0.7.5", lang: "rust"})
MERGE (a2:Package {name: "serde_json",    version: "1.0.115", lang: "rust"})
MERGE (a3:Package {name: "quick-xml",     version: "0.31.0", lang: "rust"})
MERGE (a4:Package {name: "jsonwebtoken",  version: "9.3.0",  lang: "rust"})
MERGE (a5:Package {name: "image",         version: "0.24.7", lang: "rust"})
MERGE (a6:Package {name: "reqwest",       version: "0.11.27", lang: "rust"})

// Transitive dependencies (one extra hop)
MERGE (t1:Package {name: "openssl",       version: "0.10.62", lang: "rust"})
MERGE (t2:Package {name: "memchr",        version: "2.7.1",  lang: "rust"})
MERGE (t3:Package {name: "ring",          version: "0.17.7", lang: "rust"})

// Direct edges
MERGE (svc)-[:DEPENDS_ON {scope: "direct"}]->(a1)
MERGE (svc)-[:DEPENDS_ON {scope: "direct"}]->(a2)
MERGE (svc)-[:DEPENDS_ON {scope: "direct"}]->(a3)
MERGE (svc)-[:DEPENDS_ON {scope: "direct"}]->(a4)
MERGE (svc)-[:DEPENDS_ON {scope: "direct"}]->(a5)
MERGE (svc)-[:DEPENDS_ON {scope: "direct"}]->(a6)

// Transitive edges
MERGE (a6)-[:DEPENDS_ON {scope: "transitive"}]->(t1)
MERGE (a3)-[:DEPENDS_ON {scope: "transitive"}]->(t2)
MERGE (a4)-[:DEPENDS_ON {scope: "transitive"}]->(t3)

// Published CVEs against these packages
MERGE (cve1:CVE {id: "CVE-2026-1001", severity: "high",
       description: "image: remote denial of service via crafted GIF frame counts",
       affected: "image"})
MERGE (cve2:CVE {id: "CVE-2026-1042", severity: "critical",
       description: "openssl: timing oracle in CBC decryption when used with PKCS7 padding",
       affected: "openssl"})
MERGE (cve3:CVE {id: "CVE-2026-1099", severity: "medium",
       description: "quick-xml: stack overflow on deeply nested XML if recursion guard disabled",
       affected: "quick-xml"})
MERGE (cve4:CVE {id: "CVE-2026-1188", severity: "low",
       description: "memchr: SIMD path miscompile on AVX-512 disabled by default",
       affected: "memchr"})
MERGE (cve5:CVE {id: "CVE-2026-1210", severity: "high",
       description: "jsonwebtoken: alg confusion when verifying tokens with HS256 if RS256 keys are accepted",
       affected: "jsonwebtoken"})

MERGE (cve1)-[:AFFECTS]->(a5)
MERGE (cve2)-[:AFFECTS]->(t1)
MERGE (cve3)-[:AFFECTS]->(a3)
MERGE (cve4)-[:AFFECTS]->(t2)
MERGE (cve5)-[:AFFECTS]->(a4);

Step 2: Find every reachable CVE for the service

// Walk 1..2 hops to find every CVE on a direct or transitive dep.
MATCH (svc:Service {name: "Northwind API"})-[:DEPENDS_ON*1..2]->(pkg:Package)<-[:AFFECTS]-(cve:CVE)
RETURN DISTINCT cve.id          AS cve,
                cve.severity    AS severity,
                pkg.name        AS package,
                cve.description AS description
ORDER BY severity DESC;

Step 3: Have LLM_SCORE judge real exploitability

// Now grade each CVE for whether it actually applies given how the service uses the dep.
MATCH (svc:Service {name: "Northwind API"})-[:DEPENDS_ON*1..2]->(pkg:Package)<-[:AFFECTS]-(cve:CVE)
WITH svc, pkg, cve,
     llm_score(
       "Given this service description: '" + svc.description +
       "' and this CVE: '" + cve.description +
       "', score 0..1 the chance the vulnerability is reachable in this service. " +
       "Score high only if the vulnerable code path is plausibly hit by user input.",
       cve
     ) AS exploitability
RETURN cve.id AS cve, cve.severity AS published_severity, pkg.name AS package,
       exploitability,
       CASE WHEN exploitability > 0.7 THEN "FIX NOW"
            WHEN exploitability > 0.4 THEN "investigate"
            ELSE "noise"
       END AS triage
ORDER BY exploitability DESC;

What's happening

  • [:DEPENDS_ON*1..2] walks both direct and transitive deps with one variable-length hop. *1..N extends to deeper transitive trees.
  • The published CVE severity is what most scanners report; LLM_SCORE produces an additional contextual severity that reads the service description and the CVE text to ask "is this reachable here?"
  • For the demo: the GIF DoS in image (which the API actually calls) and the JWT alg confusion in jsonwebtoken (auth code path) score high; the AVX-512 miscompile in memchr and the XML stack overflow with the default recursion guard enabled score low.
  • The triage CASE turns the score into a workflow signal — straight into ticket priority.
  • Pair with recipe 014 (cyber threat graph): export today's exploitable CVEs as :Vulnerability nodes and run attack-path analysis from your public-facing services through them.

Try this next

MATCH (svc:Service)-[:DEPENDS_ON]->(direct:Package)
RETURN svc.name, count(direct) AS direct_dep_count;
MATCH (cve:CVE)-[:AFFECTS]->(p:Package)<-[:DEPENDS_ON*1..3]-(svc:Service)
WHERE cve.severity IN ["high", "critical"]
RETURN cve.id, cve.severity, p.name, count(DISTINCT svc) AS impacted_services
ORDER BY impacted_services DESC;
// Packages with no published CVEs — the boring-good kind.
MATCH (p:Package)
OPTIONAL MATCH (cve:CVE)-[:AFFECTS]->(p)
WITH p, count(cve) AS open_cves
WHERE open_cves = 0
RETURN p.name AS package, p.version;

Tags

graphcypherllm_scoredevopssecurityadvanced

Run this on your own machine

Install SynapCores Community Edition free, paste the SQL or Cypher above into the bundled web UI, and watch it run.

Download Free CE