ai newsDi., 20. Okt.
EilmeldungThe October 2026 GTM Stack Teardown: Why Multi-Tool AI Bloat Is Draining B2B Budgets

The Nx Malware Ran Claude Code With --dangerously-skip-permissions. Could It on Yours?

Book: Prompt Engineering Pocket Guide Also by me: Thinking in Go (2-book series) — Complete Guide to Go Programming + Hexagonal Architecture in Go My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools Me: xgabriel.com | GitHub At 22:32 UTC on Au

dev.toMontag 23:01 · 19.10.7 Min. Lesezeit
Bild: dev.to

At 22:32 UTC on August 26, 2025, nx 21.5.0 went up on npm with a postinstall script called telemetry.js. Inside it, Snyk found a small lookup table:

claude: { cmd: ' claude ', args: [ ' --dangerously-skip-permissions ', ' -p ', PROMPT ] }, gemini: { cmd: ' gemini ', args: [ ' --yolo ', ' -p ', PROMPT ] }, q: { cmd: ' q ', args: [ ' chat ', ' --trust-all-tools ', ' --no-interactive ', PROMPT ] } Enter fullscreen mode Exit fullscreen mode Three coding agents, each with its approval prompts switched off, each handed a prompt asking it to find files that hold secrets. Seven more malicious versions followed over the next two hours. npm pulled them at 02:44 UTC, per StepSecurity's timeline. GitGuardian later counted 2,349 distinct secrets in the public repositories the payload created.

The flags are the part worth a second look, because the attacker picked them, not the developer.

The Nx security advisory traces the entry point to a GitHub Actions workflow that echoed a pull request title inside a run: step, under the pull_request_target trigger. A crafted title ran shell commands with a read/write token. The Nx team believes that is how the attacker got the npm publishing token.

From the StepSecurity write-up, the payload then ran in this order:

Step 2 matters for everything below. The script already ran as you, with your files and your tokens. The agents gave it no access it lacked. They gave it a search tool that adapts to whatever your disk looks like.

The damage kept going after npm pulled the versions. On August 28 a second wave used the stolen GitHub tokens to flip private repositories to public. GitGuardian counted 10,767 of them.

Okta's threat intelligence team noted that successive package versions carried at least four different prompts, as the attacker iterated. Paul McCarty at Safety reran all four on a sandboxed Mac with the same flags. Run counts vary and are often unstated: 10 runs for Claude on the third version, 5 for Gemini on the fourth, one described run for Claude on the second:

Claude refused the first version outright, quoted in the Safety post as "I cannot help with searching for and cataloging wallet-related files, private keys". Reframe the same job as a pentest and it complied on the run Safety describes. Several of the Gemini failures were sandbox or write limits, not refusals on content. It's a small sample, but with the flags held constant, wording alone swung the outcome from refusal to compliance.

The field numbers agree that the AI step was the shaky part. Of the compromised systems GitGuardian studied, 33% had at least one LLM client installed. LLM tools were targeted on 366 systems, and only 95 of them wrote /tmp/inventory.txt.

The new part is that an install script can hand the hunting to a model, and the model's refusals depend on phrasing an attacker can retry.

Claude Code's permission modes docs are clear that bypassPermissions belongs in containers or VMs. They also explain why that warning did nothing here. The first time you start an interactive session in that mode, Claude Code shows a dialog asking you to accept responsibility. In non-interactive mode, the -p the payload used, "no dialog is shown". Claude Code refuses bypass mode as root or under sudo, but the payload ran as your normal user and its own prompt said not to use sudo.

By default, any process that can run claude can choose its mode, and gemini and q work the same way. Your own ~/.claude/settings.json is no barrier either: the permissions docs let you lock yourself out of bypass mode there, but a script running as you can edit that file.

What a script running as you can't edit without a password is a file in a root-owned system directory. That is where the useful setting goes.

First, the same check the payload ran, plus a look for settings that already skip prompts:

for c in claude gemini q; do command -v " $c " > /dev/null && echo "on PATH: $c " done grep -nE 'bypassPermissions|skipDangerousMode' \ ~/.claude/settings.json 2>/dev/null Enter fullscreen mode Exit fullscreen mode A "defaultMode": "bypassPermissions" in your user settings means a script doesn't even need the flag. skipDangerousModePermissionPrompt only silences the interactive dialog, which -p never shows anyway.

Claude Code. The permissions docs say permissions.disableBypassPermissionsMode set to "disable" prevents bypass mode, and that it is most useful in managed settings. Per the managed settings docs, the file lives at /Library/Application Support/ClaudeCode/managed-settings.json on macOS and /etc/claude-code/managed-settings.json on Linux, and no user, project or --settings value overrides it. Check for an existing file with cat first, because this overwrites it:

# Linux: D=/etc/claude-code D = "/Library/Application Support/ClaudeCode" sudo mkdir -p " $D " sudo tee " $D /managed-settings.json" > /dev/null << ' EOF ' { "permissions": { "disableBypassPermissionsMode": "disable" } } EOF Enter fullscreen mode Exit fullscreen mode Two caveats from the same page. On WSL, /etc/claude-code is user-writable, so a file there alone protects nothing. And if the operating system denies the read, sessions start without the policy; /status and claude doctor record that failure.

Gemini CLI. The enterprise guide documents security.disableYoloMode: true, which forces every tool call to ask, in the system settings file at /Library/Application Support/GeminiCli/settings.json or /etc/gemini-cli/settings.json. The same guide says the path can be overridden with the GEMINI_CLI_SYSTEM_SETTINGS_PATH environment variable, and whoever launches gemini controls its environment. Treat it as a guard against accidents, not against a hostile script. Gemini CLI itself was replaced by Antigravity CLI for unpaid and Google One users on June 18, 2026, per the same page.

Amazon Q. AWS says the Q Developer CLI has been rebranded to Kiro. Check what an old q binary on your PATH still does before trusting it.

The install step. None of the above stops step 2. The way in was a postinstall script, and npm's ignore-scripts config means "npm does not run scripts specified in package.json files". npm config set ignore-scripts true turns that on for your user. Some packages need their install step, and you then run those deliberately.

I build Hermes IDE, so weigh this section with that in mind. Hermes would not have stopped telemetry.js. It isn't a sandbox, and a postinstall script doesn't go through it. The settings above are what refuse a bypass launch.

What the incident does show is why Hermes has one fixed rule: it never answers a permission prompt for you and never types into a terminal on its own ( README ). The payload worked by removing the human from the approval loop. A tool that sits between you and your agents and clicks yes on your behalf would rebuild that hole on purpose, as a feature. I made the case at more length in No Script Should Ever Click 'Allow' for Your Coding Agent.

The ⌘N New task sheet: Claude Code, the orders-api project, a new hermes/ worktree, Accept edits, model and effort chips, and the "Hermes will run" preview of the claude command.

When you start a task with ⌘N (Ctrl+Shift+N on Windows and Linux), you pick the agent, model and effort for it, and the agent runs its own interface in a real terminal, so its permission prompts reach you unchanged. When an agent does ask, the attention inbox counts it, ⌘I (Ctrl+Shift+I on Windows and Linux) jumps to the one that has waited longest, and you answer in that agent's own terminal.

Hermes is free, source-available under BSL 1.1, and runs on macOS, Windows and Linux. Download it here, and the code is on GitHub. It is not affiliated with Nous Research, Anthropic, OpenAI, Google, AWS or any other agent vendor.

The most telling detail in this incident is the Safety table: the same agent refused a request and then carried it out once the wording changed. That is prompt engineering, used against you. My Prompt Engineering Pocket Guide covers how framing and instructions shape what a model does, prompt injection included, so you can read a prompt like the one in telemetry.js and see what each line is doing.

Quelle: dev.to (dev.to). Original öffnen