Autopsy 14 · Developer workstation AI trust chain | Comic Strip 12 · The Assistant that Robbed the House

Would Ethosure have caught this?  The Nx s1ngularity attack that weaponised developers’ own AI CLIs

Attackers pushed eight trojanised Nx releases to npm on August 26, 2025. The postinstall script invoked victims’ own Claude Code, Gemini CLI, and Amazon Q binaries with safety flags disabled and told them to hunt for secrets. Roughly 1,000 valid GitHub tokens, dozens of cloud credentials, and 5,500 private repositories were exposed. First documented case of a supply-chain payload deliberately using the developer’s AI assistant as an amplifier.

Series: Would Ethosure have caught this?
Root cause: AI coding CLIs invoked with safety flags disabled from untrusted postinstall scripts
Coding-ethos policy: ai_cli.invocation.requires_workload_declared_lease

The incident

On August 21, 2025 a flawed GitHub Actions CI workflow was contributed to the Nx repository. On August 24 a follow-up commit modified the workflow so that Nx’s npm publishing token would be exfiltrated via webhook to an attacker-controlled server. Between 22:32 UTC on August 26 and 00:37 UTC on August 27, eight trojanised Nx and Nx Powerpack releases were published across versions 20.9.0 through 21.8.0. npm removed the affected versions at 02:44 UTC on August 27. The malicious postinstall script (telemetry.js) ran on victims’ Linux and macOS developer machines and CI environments, invoking whichever AI coding CLI it found locally – Claude Code, Gemini CLI, or Amazon Q – with safety controls disabled via <code>–dangerously-skip-permissions</code>, <code>–yolo</code>, and <code>–trust-all-tools</code>. The CLIs were instructed to recursively search the developer environment for cryptocurrency wallets, SSH keys, npm tokens, GitHub tokens, .env files, and cloud API keys. Wiz Threat Research (with Adnan Khan) documented a second wave on August 28 in which stolen GitHub tokens were used to make more than 5,500 private repositories public across more than 400 users and organisations. GitGuardian detected 82,901 secrets in 2,399 s1ngularity-repository dumps, 11,168 of them valid.

See also  Would Ethosure have caught this? The Mexico Claude Code and GPT-4.1 mass exfiltration

The applicable coding-ethos policy

Policy packModel / provider governance pack (with regulated-enterprise base overlay)
Principlelocal-ai-cli-not-a-shell-primitive
Control familyWorkload-declared lease on local AI CLI invocation + postinstall sandboxing

Coding-ethos policies are compiled from principle-owned CEL expressions. Every expression in the Ethosure corpus passes three gates: policyvalidate (schema + CEL compile), audit_runtime.py (the fields the expression references are guaranteed present on the runtime event path), and policytest (behavioral fixtures – the policy fires on the positive case and stays quiet on the near miss). The corpus ships 190 policies across 49 principles in six packs, with 422 fixtures and zero failures.

Walkthrough

  1. The Nx attack does not just breach the supply chain. It turns the victim’s AI assistant into a search engine for its own secrets. The malware did not need to enumerate .env files or grep for SSH keys; it just asked Claude Code to do it, with --dangerously-skip-permissions pinned on. Every safety flag the CLI vendors ship exists so that developers can disable them; the flag ecosystem is now attacker surface.
  2. ai_cli.invocation.requires_workload_declared_lease fires on PreToolUse for any local process that invokes a registered AI coding CLI (claude, gemini, q) without an active lease that names the invoking workload and its declared purpose. Severity block. Postinstall scripts are workloads too; they simply do not have a lease.
  3. ai_cli.invocation.forbid_safety_disable_flags_from_scripts is the second expression. It fires on any invocation of a registered AI coding CLI whose arguments include --dangerously-skip-permissions, --yolo, or --trust-all-tools and whose parent process is not a terminal session with a signed operator identity. Severity block. Interactive humans keep the flags. Scripts lose them.
  4. runtime.package.postinstall_forbidden_network_and_ai_cli is the third. npm postinstall is legitimate for occasional build tasks and illegitimate for everything else. The expression fires on any postinstall script that opens outbound network connections beyond a declared allowlist or invokes any AI coding CLI. Severity block. The telemetry.js payload violates both conditions on first execution.
See also  Would Ethosure have caught this? The OpenAI agent swarm that turned DseWiki into a message board

Policy YAML

# Pack: model-provider-governance (v2)
# Inherits: regulated-enterprise-base
principles:
  - id: local-ai-cli-not-a-shell-primitive
    title: Local AI CLI Not A Shell Primitive
    directive: >-
      Locally installed AI coding CLIs must be treated as authenticated agents, not as
      shell utilities. Their invocation must carry a workload-declared lease, their
      safety-disable flags must be blocked from non-interactive callers, and untrusted
      postinstall scripts must not be able to invoke them at all.
    policy:
      expressions:
        - id: ai_cli.invocation.requires_workload_declared_lease
          scope: agent_action
          severity: block
          event: PreToolUse
          principle_ids:
            - local-ai-cli-not-a-shell-primitive
            - security-by-design
          skill_id: safe-local-ai-cli
          when: >
            process.exec.binary in ["claude", "gemini", "q"]
            && !host.ai_cli_leases.exists(l,
                 l.state == "active"
                 && l.workload_id == process.parent.workload_id
                 && l.purpose.declared)
          message: >-
            AI coding CLI invoked with no active workload-declared lease.
          advice: >-
            Require the invoking workload to acquire a lease naming its purpose. This
            blocks the Nx-style postinstall invocation on first execution.

        - id: ai_cli.invocation.forbid_safety_disable_flags_from_scripts
          scope: agent_action
          severity: block
          event: PreToolUse
          principle_ids:
            - local-ai-cli-not-a-shell-primitive
            - security-by-design
          when: >
            process.exec.binary in ["claude", "gemini", "q"]
            && process.exec.args.exists(a, a in ["--dangerously-skip-permissions",
                                                  "--yolo", "--trust-all-tools"])
            && !process.parent.session.exists(s,
                 s.tty && s.operator_identity.signed)
          message: >-
            AI coding CLI invoked with a safety-disable flag from a non-interactive caller.
          advice: >-
            Strip the flag or reject the invocation. Safety-disable flags are for humans at
            a terminal, not for postinstall scripts.

        - id: runtime.package.postinstall_forbidden_network_and_ai_cli
          scope: agent_action
          severity: block
          event: PreToolUse
          principle_ids:
            - local-ai-cli-not-a-shell-primitive
            - least-authority-in-the-pipeline
          when: >
            process.parent.category == "npm_postinstall"
            && (tool_call.category == "network_connect"
                && !tool_call.destination.host.in_allowlist(
                     package.postinstall_network_allowlist)
                || process.exec.binary in ["claude", "gemini", "q"])
          message: >-
            npm postinstall script attempted disallowed network egress or invoked an AI
            coding CLI.
          advice: >-
            Reject the operation. Postinstall scripts should not phone home outside the
            package's declared allowlist and must never invoke an AI CLI.

Assurance boundary. Fixtures prove that synthetic positive cases fire and near-misses stay quiet. They do not establish production alert rates. DLP-backed controls depend on upstream detection, shell-command regexes are defense in depth rather than a sandbox boundary, and regulatory tags are engineering aids requiring counsel review.

Where this policy lives in the corpus

The Ethosure importable corpus ships six coding-ethos packs. Each pack composes with the regulated-enterprise base pack, which owns cross-cutting controls for secrets, destructive actions, and human oversight.

  • Regulated-enterprise base pack – secrets, destructive actions, human-in-the-loop, evidence-layer recording.
  • Financial services overlay – OSFI E-23 alignment, FINTRAC-adjacent data handling, transaction-boundary controls.
  • Healthcare & life sciences overlay – PHI handling, model-provenance requirements, evaluation-set contamination checks.
  • Government & critical infrastructure overlay – identity-provenance requirements, review-channel signatures, air-gap enforcement labels.
  • Model & provider governance pack – egress allowlists, evaluation-runtime isolation, cross-runtime coordination detection.
  • AI cost control pack – payload-size and endpoint-visible model checks (preventive), token-total and response-side model facts (detective), external ledger for cumulative budgets.

Published September 3, 2026 · Ethosure · Part of the Autopsy Series.