{"schema_version":"1.9.2","id":"MAL-2026-17630","published":"2026-10-03T22:47:45Z","modified":"2026-10-29T13:48:11.582312515Z","summary":"Malicious code in virgil-cli (npm)","details":"In local mode virgil-cli prints that it runs on the user's machine and is free and private. After each turn, reportLearning() in dist/api.js posts the whole conversation history, including shell and file tool output, to https://api.nm-streetwear.space/vx/learn with a hardcoded token and a device id. I found no mention of this in the README and no setting to turn it off. I did not see it read credentials itself, but tool output can contain secrets. I read 0.1.4 only and did not run it.\n\n---\n_-= Per source details. Do not edit below this line.=-_\n\n## Source: amazon-inspector (a603c1f5f6674c45322b6017e44aa35a824a3c4d57ecf9571b214276b2538624)\nvirgil-cli is an AI agent command-line tool whose README advertises that it 'runs commands' on the user's machine. On explicit CLI invocation (not on npm install or require), api.js POSTs the conversation to a hardcoded control plane at https://api.nm-streetwear.space/vx/agent using a shared static token 'virgil-ext-8528'. The server's response includes tool_calls that loop.js dispatches locally, including a run_shell tool implemented in runShell.js as child_process.spawn(command, { cwd, shell: true,... }). A per-command confirmation prompt exists but is bypassed by the documented --auto / -y flag and by an 'always allow' persistence option. The baseUrl is overridable via ~/.virgil/config.json. Separately, when local-Ollama inference is configured, api.js reportLearning() POSTs the full message history (including read_file contents, run_shell stdout/stderr, and list_dir output harvested from the user's machine during the session) to https://api.nm-streetwear.space/vx/learn after every turn, despite setup.js framing local mode as a privacy option. The destination is the vendor's own first-party endpoint and user-reconfigurable; the shared static bearer token offers no per-installer authentication, so any party able to reach the control plane or MITM the TLS channel can direct shell execution on hosts running the CLI, and the local-mode transcript upload contradicts the local-only privacy framing.\n","affected":[{"package":{"name":"virgil-cli","ecosystem":"npm","purl":"pkg:npm/virgil-cli"},"versions":["0.1.4"],"database_specific":{"cwes":[{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"}],"indicators":{"evidence_files":[{"path":"dist/tools/runShell.js","sha256":"1e3783043e06df3289c70acfd26966a24b65083c2739daff551ffa9ca7c16f3a","tlsh":"5a51250f15bb1268137375ac476fb816729022039569dea8fe5fad102f46624e0f2bf5"},{"path":"dist/api.js","sha256":"757088f2bdf2b9d66267833a2db540dc3b1fb209c24ce0ecacf10c5a5bd09059","tlsh":"8bc1b8e744b32a36069fb19de75f10527629a1071c8d9c40bb8c41589f8c06f4bfafe4"}],"package_integrity":[{"filename":"virgil-cli-0.1.4.tgz","hashes":{"sha1":"f10f1c7b773a9e4bf53acf553e14305f07dd8299","sha512_sri":"sha512-0qiTJHzC1SPP/k6UqLL8/E6+fvU9Q9Fo+h0c+sNWacVAcz7m5qrKsnaqQlYMpczL/nzO+3ebdU8zP752LlUfiA=="}}]},"source":"https://github.com/ossf/malicious-packages/blob/main/osv/malicious/npm/virgil-cli/MAL-2026-17630.json"}}],"references":[{"type":"PACKAGE","url":"https://www.npmjs.com/package/virgil-cli/v/0.1.4"}],"database_specific":{"iocs":{"domains":["api.nm-streetwear.space"],"urls":["https://api.nm-streetwear.space/vx/learn"]},"malicious-packages-origins":[{"id":"IN-MAL-2026-021966","import_time":"2026-10-29T13:37:18.217662653Z","modified_time":"2026-10-29T13:31:21Z","sha256":"a603c1f5f6674c45322b6017e44aa35a824a3c4d57ecf9571b214276b2538624","source":"amazon-inspector","versions":["0.1.4"]}]},"credits":[{"name":"Amazon Inspector","contact":["inspector-research@amazon.com"],"type":"FINDER"},{"name":"smiling-hyena","contact":["smilinghyena4@gmail.com"],"type":"FINDER"}]}