
Elastic: A Coding Agent Was the Trusted Parent of a Session That Looked Like C2
- OrcaNEWOrcaCyber: MiniMax M3.1 Flash Abliterated / Uncensored2026-10-29101 tok/s
- OrcaNEWOrcaCyber: GLM 5.3 Flash Abliterated / Uncensored2026-10-27$0.80 / $1.60 per 1M tokens · 103 tok/s
- OrcaNEWOrcaCyber: Qwen3.8 Flash Next Abliterated / Uncensored2026-10-26$0.80 / $1.60 per 1M tokens · 291 tok/s
- OrcaNEWOrcaCyber: MiMo V2.6 Flash Abliterated / Uncensored2026-10-26$0.80 / $1.60 per 1M tokens · 94 tok/s
- MoonshotNEWMoonshotAI: Kimi K3.1 Pro2026-10-2446Intelligence
- OrcaNEWOrcaCyber: DeepSeek V4.1 Flash Abliterated / Uncensored2026-10-23$0.80 / $1.60 per 1M tokens · 107 tok/s
- minimaxNEWMiniMax: M3.1 Flash2026-10-1929Intelligence
- OrcaNEWOrca: OrcaCyber Ultra 1.02026-10-17$5.00 / $10.00 per 1M tokens · 71 tok/s
- deepseekNEWDeepSeek: DeepSeek V4.1 Flash 10172026-10-1733Intelligence
- DeepSeekNEWDeepSeek: DeepSeek V4.1 Flash2026-10-1740Intelligence
- OrcaOrca: OrcaCyber Zero 1.52026-10-10$3.00 / $7.50 per 1M tokens · 96 tok/s
- openaiOpenAI: GPT-6.1 Sol2026-09-2955Intelligence
- anthropicAnthropic: Claude Sonnet 5.52026-09-2854Intelligence
- typesafeTypeSafe: Jev 1.132026-09-24$0.04 / $0.00 per 1M tokens · 172 tok/s
- OpenAIOpenAI: GPT-6 Luna2026-09-2228Intelligence
- OpenAIOpenAI: GPT-6 Sol2026-09-2248Intelligence
- AnthropicAnthropic: Claude Opus 5.52026-09-2258Intelligence
- xiaomiXiaomi: MiMo-V2.6-Flash2026-09-2127Intelligence
- xiaomiXiaomi: MiMo-V2.6-Pro2026-09-2130Intelligence
- xAIGrok 4.72026-09-2134Intelligence
On 23 July 2026, two separate hunting paths inside Elastic Security Labs landed on the same macOS developer machine. One began with a domain-reputation hit on a hostname contacted under a coding agent's process lineage; the other with correlated endpoint alerts, among them a production rule Elastic calls Persistence via GenAI Tool. What the two paths found was published on 7 August 2026 in "Living off the coding agent: Two tales of tunnels and LaunchAgents", by Mika Ayenson and Jia Yu Chan: a Claude Code session, started with the permission-bypass flag --allow-dangerously-skip-permissions, whose child shells authenticated against free tunnel brokers, published a localhost service through a Cloudflare Quick Tunnel, and installed a LaunchAgent watchdog to keep that tunnel alive across logout and reboot. Elastic does not call it an intrusion. It calls it a window that "teeters between two readings that share the same telemetry shape". The archive files the episode as a research finding — medium severity on its own scale, A-grade confidence, no recorded real-world harm, dated to a single day — and the Orca AI Incident Archive carries the entry with Elastic's report cited beneath it.
The word Elastic uses for the pattern is not "malware". It is "living off the coding agent" — the same family of behaviour as living off the land, with the trusted binary replaced by a tool the developer installed on purpose. Claude Code and Cursor are vendor-signed and sit on developer laptops all day. They open shells, call APIs, edit files and install helpers. The parent looks trusted. The children, Elastic writes, "can still look a lot like classic high-severity activity".
The four days Elastic could see
Elastic's account covers a telemetry window that opens three days before the two hunts converged. Each day is worth reading separately, because the sequence rather than any single event is what Elastic treats as diagnostic.
20 July 2026. Elastic Defend raised malicious_file detections on tunnel and VPN-class binaries: pritunl-client first, wireguard-go later. Elastic is explicit that these classifications can be dual-use noise, and that their significance comes from what surrounded them.
21 July 2026. A process tree read zsh, then python3 running /tmp/mcp_clean_landers.py, then a redacted domain. There was outbound HTTPS to analytics.[redacted].dev. Elastic describes the script's shape as plaintext MCP-style JSON-RPC analytics requests used to retrieve data, and says plainly that this is not evidence of data being sent out. In the same window a generic cat process read a Claude project memory file, ~/.claude/projects/*/memory/MEMORY.md, outside the usual Claude writer. One reading Elastic offers is an agent updating its own durable context.
22 July 2026. A spike in the building-block rule GenAI or MCP Server Child Process Execution. Elastic treats this as ancestry and timing context, not as an outcome, because such children are often ordinary tooling.
23 July 2026. The day of the record. Credential-bearing HTTP to lhr[.]life and trycloudflare hostnames, cloudflared, LaunchAgent activity and a malicious_file detection on an ngrok binary all sit in the same session window. The earliest ngrok hit came under zsh; later activity appeared under launchd.

A loop that waits for a 200, then logs in
The command-line detail is where the report earns its title. A shell loop polled https://[id].lhr[.]life/login until the response came back HTTP 200, then POSTed user=...&password=..., then made a cookie-authenticated request to /api/summary?from=...&to=... piped through jq to extract the spend field. A parallel set of requests went to https://[name].trycloudflare[.]com/login and pulled back spend and ads. Response bodies were discarded with -o /dev/null while the loop checked authentication. Session files sat under /tmp, and status strings in the wrapper included the Cyrillic проверка, meaning "check".
Elastic lists three features it considers suspicious: credentials written into a process command line, plaintext credentials sent over an anonymised free-tunnel URL, and the loop-until-200 pattern. It immediately sets the other reading beside them — a developer self-testing an application they had just published, which would produce a similar shape.
The publishing step used cloudflared. Elastic's reconstruction gives the typical invocation as cloudflared tunnel --url http://localhost:[port], though it notes the process arguments were not captured. Control-plane contact went to api.trycloudflare[.]com. The mechanism matters more than the syntax: a Quick Tunnel exposes a laptop service to the public internet through an outbound-only channel, with no inbound firewall change. Elastic's endpoint matched it to the rule Unusual Network Connection to Suspicious Web Service. An ngrok binary also sat in the project tree, carrying the hash d335a47a04dde726897a2e753187e9f48fbf40616c48be3266954c7b9175a09e, which VirusTotal labels adware/hacktool ngrok.
On reputation, Elastic is cautious. VirusTotal's results for the lhr[.]life apex carried malicious and phishing labels and community tags suggesting potential command-and-control use. But the unbound apex page displayed "no tunnel here". Elastic's position is that neither the labels nor the empty page resolve anything: one does not clear the alert, the other does not confirm abuse.
Persistence is where the shells stop disappearing
Shells and temporary files go away when a session ends. LaunchAgents do not, which is why Elastic's write-up gives them the most weight. A watchdog property list was configured with PlistBuddy setting :StartInterval 60 on ~/Library/LaunchAgents/com.[vendor].[app].watchdog.plist, then reloaded with launchctl bootout and launchctl bootstrap against the user's GUI domain. Sibling agents shared the com.[vendor].[app]. family, with role names including server, ngrok, lhr, tunnel and watchdog. A liveness loop curled the tunnel's login page on an interval. With KeepAlive set and a liveness loop attached, the access outlives the terminal that created it. The behaviour-prevention rule Persistence via GenAI Tool fired on this.
Two other pieces round out the session. A pgrep sweep for related workloads is low severity on its own, but in sequence it looks like checking that sibling services are still up; that mapped to Process Discovery via Built-In Applications. And the GenAI child-process building block recorded a command reading security find-generic-password -a [user] -w -s "Claude Code-credentials", which prints Claude Code's OAuth token to standard output. Elastic notes, rather than glosses over, that Claude Code's own issue 81707 documents this as expected behaviour — the command is not a flaw in the agent, even though it is exactly what a credential thief would run.

Three related variants, and what they add
Elastic describes three further variants beyond the primary endpoint. In the first, Claude Code is the effective parent while Apple-signed Python and osascript drop and re-run JavaScript from /tmp — a living-off-the-land-binaries staging trick. In the second, a Cursor session attempted a decrypted keychain dump filtered toward Linear and Model Context Protocol OAuth material; endpoint controls blocked it, and Elastic maps the attempt to T1555.001. In the third, Claude Code running with the permission bypass pulled an unsigned binary over plaintext HTTP, attempted quarantine stripping and ad-hoc re-signing, and probed ~/.zshenv as a persistence canary, mapping to T1105.
Those cases are reported as related rather than proven to share an operator. Elastic does not tie them to one actor, and nothing in the report establishes that the primary host and the variants were driven by the same person.
What is established, and what Elastic does not claim
The telemetry described above is established as a record of what Elastic's own product saw, with one caveat that the report itself never hides: the case comes from Elastic Defend, the endpoint product whose rules are being evaluated. The company is reporting on its own instrument, and the identifiers that would let anyone else check the finding are redacted — the host is "a macOS developer endpoint", the domains are analytics.[redacted].dev, the request target is [id].lhr[.]life.
What the report does not establish is substantial. It gives no count of hosts, endpoints or customers: the primary case is one machine, with related cases mentioned on other hosts and never tallied. It does not identify the machine, its owner or the organisation. It does not establish that any data left the host; the 21 July analytics traffic is described as resembling retrieval, not exfiltration. And it does not establish intent. Elastic's own instruction to analysts is to "treat that as high severity even when it looks like vibe-coded ops, not confirmed malware" — the high severity is an argument about response, not a finding about the operator.
Independent corroboration is thin, and it is worth saying so plainly. Every secondary write-up located for this piece — Cyber Security News on 10 August 2026, zerowl.io on 11 August 2026, and the aggregator entries around them — restates Elastic's facts and cites Elastic. None reports separate access to the telemetry, and the searches run for this piece surfaced no regulator or platform-vendor notice, advisory or correction concerning the activity. The archive grades the record A for confidence and false for real harm; neither grade supplies a second pair of eyes.

Where the archive entry goes further than the report
The archive's summary frames the case as a structural property of agentic coding tools: they combine "everything an attacker needs access to" — environment variables, credentials, API keys, local config — with "continuous ingestion of untrusted content" such as repositories, documents and error messages. That argument is plausible and widely made elsewhere, but it is not Elastic's. The report's framing is narrower and more mechanical: a vendor-signed parent produces children that resemble high-severity activity, and analysts triage the children on the parent's reputation. Elastic's sentences are about trust placement, not about prompt injection or the untrusted-content boundary.
Two other labels are worth keeping straight. The archive dates the record to 23 July 2026, the day the two hunt paths converged; Elastic's telemetry window opens on 20 July and its report was published on 7 August. And the archive grades severity medium, while Elastic's instruction to defenders is to treat the outcomes as high severity rather than auto-close them. Those are two different scales — an archive's assessment of a documented finding, and a detection vendor's alert-handling guidance — and neither is a correction of the other.
What Elastic tells defenders to do
• Do not automatically close credential-bearing HTTP, reverse tunnels or LaunchAgents because Claude or Cursor appears in the process tree. The parent's trustworthiness is the disguise, not the mitigation.
• Classify the destination early. localhost.run, Cloudflare Quick Tunnels and ngrok are dual-use infrastructure; record which class was contacted before leaning on rare-TLD or VirusTotal reputation labels.
• Prefer session context to single-event reputation. A readiness loop, a publish-localhost step followed by /login and /api/summary calls, and persistence that keeps a tunnel alive are stronger pivots than an apex page reading "no tunnel here".
• Keep volume and outcome apart. GenAI child-process building blocks are ancestry and timing context until secrets, tunnels or persistence appear in the same session.
• Document both plausible readings where the evidence supports both, and say what the telemetry cannot decide.
Elastic's conclusion is not a verdict. It is that "no single production rule owns the full sequence", that the production rules which fired cover different parts of it, and that the analyst has to correlate endpoint outcomes with ancestry before deciding. In the material reviewed for this piece, Elastic has not published a follow-up identifying the host, the operator or which of the two readings turned out to be true — so the 23 July window remains, as the report left it, an ambiguity with a well-documented shape.
