Skip to content

Response, New York. Noah Park: Check Point Patches Actively Exploited Management Server Path Traversal. Detection, Dallas. Ava Okello: Report Finds Nearly Half of Deployed Detections Need Attention Before SOCs Can Trust Them.

SOCtember

Always First. Fast SOC News.

Huntress illustration of a dark control room with a large monitor showing a cloud icon connected to stacks of servers and data panels, lit in blue and pink.
Illustration: Huntress, header image for "AI, Scripts, Operator: Inside the ConnectWise Attack," Oct. 26, 2026 (fair use).

Detection

Huntress Reconstructs the ConnectWise Attack Minute by Minute and Finds Tooling Rewritten Between Runs in Under a Minute, a Pattern It Says Fits an AI Agent but Cannot Prove

Entra logs from Huntress-monitored tenants show a sorted loop across almost 1,000 Microsoft 365 tenants, a thread pool firing up to 21 requests a second and a retry loop that appeared 55 seconds after a failed certificate upload. Huntress says defenders should alert on what the activity does, not how fast it moves.

Ava Okello, DetectionLondon6 min read

LONDON - The first run of the tool ended in failure. A certificate upload was rejected because its thumbprint did not match, and the run stopped there. Fifty-five seconds later the same tool ran again, this time with a retry loop it had not had before, and it kept trying until the upload worked.

That small change sits at the center of a new analysis from Huntress of the Oct. 15 intrusion that used a stolen ConnectWise Cloud Backup credential to reach Microsoft 365 tenants. Microsoft has attributed the activity to Storm-0940, a China-aligned actor it says used ARTEX, an open-source framework in which AI agents run an intrusion with little human input. Huntress, which first reported the credential abuse on Oct. 16, set out to answer a narrower question from its own logs: who, or what, was doing the typing.

Its answer, published Monday by Jonathan Semon and Rich Mozeleski, is a working hypothesis rather than a verdict. Scripted tooling did most of the work, Huntress says, while something adapted that tooling between runs, quickly. That something may well be an agent. On its own telemetry, Huntress puts its confidence that a large language model was involved at low to medium; taking Microsoft's attribution into account, it puts it at medium to high.

What the logs could and could not show

Huntress worked from Entra ID sign-in logs and directory audit logs in the tenants it monitors, plus fleet-wide sweeps run during the incident. That shows timing, order and shape, but it leaves gaps. Microsoft Graph reads are not recorded in the Entra audit log, and no victim Huntress knows of had Graph activity logging turned on. Application-only audit events carry no source IP address. And Huntress has no view of the actor's own systems, so it cannot see the tooling or whether a model provider sat behind it.

Huntress chart titled One day, three modes of operation, plotting activity on Oct. 15, 2026, in UTC in Huntress-monitored Microsoft 365 tenants, with bars color-coded as scripted automation, operator-driven activity and runs after the targeted app was deleted.
Chart: Huntress, "AI, Scripts, Operator: Inside the ConnectWise Attack," Oct. 26, 2026 (fair use).Activity on Oct. 15 grouped by behavior.

Most of what Huntress could see happened on Oct. 15, in a little under 14 hours, and it falls into three kinds of behavior.

The first was plain scripting. Between roughly 06:13 and 08:46 UTC, the credential was used against almost 1,000 tenants, one after another in ascending tenant ID order, one token request per tenant spaced one to six minutes apart, always with the user agent Python-urllib/3.12. Nine minutes before that loop began, about 100 failed token requests hit the first 100 tenants on the same list within 10 seconds, the signature of a thread pool firing in parallel without reading responses. The same tool ran a second time against 100 tenants with a different application's key at 13 to 21 attempts a second. Both runs used secrets that belong to a single tenant and cannot authenticate anywhere else, and the tool kept firing anyway.

The second was trial and error. Between 03:42 and 03:57 UTC, a secret was added, removed and added again; a certificate upload failed; the operator fell back to a secret, then granted and removed the Global Administrator role twice. The same sequence ran in a second tenant 47 seconds later. When that tenant refused a Global Administrator removal, the actor granted a different role to a sibling service principal, and the original service principal was deleted.

The third looked like a pilot followed by a batch. Between about 09:25 and 12:35 UTC, one sweep touched 17 tenants, one Graph token request each, in a hand-ordered sequence with irregular spacing. A second sweep at 13:54 UTC ran a fixed probe of six resources per tenant, four seconds per tenant. Huntress saw the try-one-then-batch pattern three times across two sets of tooling.

Why it might be an agent

Huntress diagram titled Tooling changed three times in one escalation session, showing five steps: a certificate upload that failed on a thumbprint mismatch at 03:48:24 UTC with no retry, a run 55 seconds later that added a retry loop, retries at 3.5 and 7.1 seconds until the upload succeeded, a second tenant where both keys were added in one run, and a refused removal that led to a role change on a sibling principal.
Diagram: Huntress, "AI, Scripts, Operator," Oct. 26, 2026 (fair use).How the escalation tooling changed between runs.

The certificate upload that failed at 03:48:24 UTC ended its run with no retry. The next run, 55 seconds later, retried the same error at 3.5 seconds and then 7.1 seconds until it succeeded, and carried the retry into the second tenant. Either someone edited the code in under a minute, Huntress writes, or a prepared tool had a retry option nobody had used yet. The speed is consistent with an agent loop that reads a failure, rewrites the call and runs it again. Doubling the wait between attempts is also the kind of defensive error handling that generated code tends to add unprompted.

Other details point the same way without settling anything. The first enumeration began around 01:05 UTC, and credential changes in the first tenant were complete by 03:50 UTC, in line with Microsoft's report of under three hours from targeting to privileged access. One tool identified itself as python-requests/2.31, where the library's default string is python-requests/2.31.0, and on Oct. 13 a browser user agent was missing its standard "(KHTML, like Gecko)" segment. Both fit a model producing user agents from memory, Huntress notes, and both fit a person copying them from documentation.

The strongest evidence against a fully autonomous agent came after 03:57 UTC. The Teams service principal had been deleted, yet for the next 22 minutes requests using it kept firing every four to eight seconds, rejected each time. An agent watching its own output would be expected to stop. A multi-agent framework leaving background tasks running could explain it, and so could a person who started some loops and walked away.

Huntress saw the same infrastructure named in ConnectWise's advisory, 144[.]172[.]64[.]128 for application sign-ins and Graph activity and 144[.]172[.]64[.]99 for a cross-tenant password spray between Oct. 10 and 14 that Microsoft also attributes to Storm-0940. It also saw the curl/7.88.1 user agent, the version that ships with Debian 12, on which the official python:3.12 container image is built. Microsoft counts more than 2,250 tenants; Huntress sees only the ones it protects.

What SOC teams can do now

Huntress table titled How scripts, people, and AI agents look different in logs, comparing pacing, response to errors, variety of requests and user agent across scripted automation, a human operator and an LLM agent in the loop.
Table: Huntress, "AI, Scripts, Operator," Oct. 26, 2026 (fair use).Huntress analyst heuristics, which the company says are not an industry standard and can overlap.

Huntress's larger warning is that the clues it relied on, a retry that appeared 55 seconds after a failure, a fixed beat between requests and hand-edited user agents, are the first things a better tool will smooth away. What holds up is what the activity does.

  • Alert when a service principal assigns itself Global Administrator or Privileged Role Administrator, when it deletes itself, and when one vendor principal grants a role to a sibling.
  • Alert on credential additions to high-privilege applications from unexpected sources.
  • Baseline each vendor application's normal user agent, source ranges and cadence. For the ConnectWise applications the normal user agent is kiota-dotnet; a vendor app departing from its baseline was the clearest early signal here.
  • Turn on Microsoft Graph activity logs where licensing allows, and keep raw user agent strings and sub-second timestamps, since normalization destroys the cadence and retry timing that proved most useful.
  • Watch across tenants, not only within one. A trickle in a single tenant can be one campaign running at thousands of attempts a minute across an estate.
  • Search sign-in and audit logs for 144[.]172[.]64[.]128, 144[.]172[.]64[.]99 and 144[.]172[.]64[.]60, which ConnectWise and Microsoft list, and for 194[.]165[.]16[.]21, which Huntress flags only as a possible link.

Sources:


Ava Okello covers detection engineering, EDR telemetry, and SOC hunting for SOCtember from London.

Related stories

Detection desk