---
id: "MAL-2026-17630"
kind: "package"
aliases: ["MAL-2026-17630"]
title: "Malicious code in virgil-cli (npm)"
severity: "critical"
cvss: null
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "virgil-cli", "fixed": [], "affected": "= 0.1.4", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["malicious", "package"]
not_affected_if: []
published_at: "2026-10-03T22:47:45+00:00"
first_seen_at: "2026-10-29T14:24:38+00:00"
updated_at: "2026-10-29T14:25:47+00:00"
sources: [{"source": "osv-malicious", "url": "https://osv.dev/vulnerability/MAL-2026-17630", "first_seen_at": "2026-10-29T14:24:38+00:00"}]
---

# Malicious code in virgil-cli (npm)

## Affected

- npm:virgil-cli affected = 0.1.4 fixed ?

## Timeline

- 2026-10-29T14:24:38+00:00 osv-malicious https://osv.dev/vulnerability/MAL-2026-17630

## From the sources

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.

---
_-= Per source details. Do not edit below this line.=-_

## Source: amazon-inspector (a603c1f5f6674c45322b6017e44aa35a824a3c4d57ecf9571b214276b2538624)
virgil-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.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
