Wiz 披露 ARTEX 智能体被 Storm-0940 用于攻击 IT 和软件厂商
ARTEX in the Wild: Storm-0940 Expands Targeting of IT and Software Vendors
Wiz 披露 2026 年 10 月有攻击者使用开源自主渗透测试框架 ARTEX 针对多家 IT 和软件厂商,活动与微软报告的中国国家级关联组织 Storm-0940 重叠,并已扩展到其他软件领域的供应链攻击尝试。
Wiz 基于自家日志复盘了开源 AI 渗透测试框架 ARTEX 被实战滥用的完整手法,给出了可复用的检测规则和 IOC。
Throughout October 2026, we identified an actor using tooling associated with ARTEX, an autonomous AI penetration-testing agent, to target multiple IT and software vendors. The activity focused on identity providers (Okta, Entra, Cognito) and abuse of Microsoft 365 integrations. We observed repeated attempts to uncover authentication bypasses, enumerate APIs, and access customer data (of the targeted vendors) across multiple environments.
Our observations overlap with Microsoft's recent report on Storm-0940, a Chinese-state aligned actor - linked to the recent supply-chain attack involving stolen vendor credentials and downstream Microsoft 365 tenants. \
However, we have additionally observed the same infrastructure, tooling, and attack patterns targeting the sector as a whole. Pivoting on identified TTPs and IOCs, we have also identified the same actor expanding their attempted supply chain compromises into other software sectors.
In this blog, we will describe the repeatable patterns and methodologies the ARTEX-using actor applied across multiple environments and cloud providers, with examples taken from real world attacks.
What is ARTEX?
ARTEX is an open-source autonomous penetration testing framework. A Chinese developer published it on GitHub in July 2026, and it won Baidu's "Agent+" red team challenge that September. In practice, an operator supplies a target and an objective. A planner agent then chooses the next step, worker agents run tools like nmap, curl, and Impacket, and every result feeds a shared graph of assets and findings.
Attackers picked it up within weeks. ARTEX artifacts surfaced in attacks on South Korean banks in late September and attacks on Japanese companies in October. Microsoft and Zscaler have since tied it to two separate actors. The developer made the tool closed-source on October 8. By then, the code had more than 12,000 forks.
A repeatable playbook
Across the investigated environments, we observed a consistent sequence of reconnaissance and attack attempts:
Map the application: Download JavaScript bundles, exposed source maps, runtime configurations, and Swagger/OpenAPI documentation to discover internal API routes and application functionality.
Probe authentication: Repeatedly initiate sign-in flows, manipulate OAuth callbacks and state parameters, test unsigned JWTs, and probe SSO and Microsoft 365-specific endpoints.
Attack identity providers and login flows: Password-spray corporate Okta and Entra ID environments, and target internal and proprietary application login pages.
Abuse account recovery: Repeatedly invoke password-reset, username-recovery, activation, and reset-token endpoints.
Test tenant isolation: Register accounts using disposable email addresses where possible, then manipulate predictable identifiers to probe for broken access controls and unauthorized cross-tenant data access.
Adapt to defense mechanisms: Rotate IP addresses when blocked, and constantly circulate user agents.
What it looked like in the logs
We analyzed these attack patterns using HTTP access logs collected via Wiz Agentless Workload Detection, alongside identity provider logs such as AWS Cognito events, Entra sign-in activity, and Okta authentication logs.
Targeting Internal Applications
The agent's first move across all observed instances of the attack was always to read the application itself. Requests like these showed up minutes after first contact:
Not long after, it started calling internal API routes by name. The only place those route names appear is in the source maps it had just downloaded.
Account recovery got the same treatment. The agent checked which usernames existed, then hammered the reset endpoints:
Where it could sign up, it did, using a throwaway mailbox from a free temporary-email service. Then, it immediately tried to look at someone else's data:
Before every fuzzing run, it checked what a baseline "not found" response looked like:
Targeting OAuth Identity Providers
When probing Microsoft OAuth flows, the agent directly manipulated the callback endpoint by injecting fabricated authorization codes and malformed state parameters, while also attempting to bypass authentication using unsigned JWTs:
That second token simply decodes to {"alg":"none"} and {"email":"test@test.com"}. The agent bombarded more than 60 variations of SSO routes with this payload in just two minutes.
On AWS Cognito, we observed patterns mirroring the account recovery abuse seen in proprietary apps. This activity was reflected in events like InitiateAuth, ForgotPassword, and ResendConfirmationCode. These requests originated from the same mix of user agents observed in earlier attacks, including benign-looking programmatic clients like boto and python-urllib.
The agent also attempted to provision new identities directly, invoking the AWS Cognito SignUp API while cycling through its pool of user agents.
Password Spraying
We also tracked a massive password spray campaign across many of the observed targets. The activity was IDP-agnostic, hitting both Entra and Okta, and displayed several unique, AI-driven characteristics.
The attacks targeted hundreds of users and were executed in highly coordinated bursts. Each burst featured:
Dedicated user agents: A unique user-agent string was assigned to each burst, distinct from those used in previous waves.
Precise timing: The median gap between authentication attempts was strictly one second.
Sustained execution: Individual bursts lasted anywhere from 20 to 60 minutes.
Role-based targeting: The agent primarily focused on accounts belonging to software engineers.
Repeated attempts: Some individual users were subjected to more than a dozen login attempts.
Relentless by Design
The activity was persistent and highly automated. Some sessions lasted 24–30 hours, and when IPs were blocked, new addresses appeared within minutes.
In one session, the agent cycled through a dozen variations of the same SSO endpoint (/sso, /sso/, /sso/login, /sso/jwt, /jwt/sso…), each with and without the same forged token, at a rate of about one request per second. When a login page started rate-limiting the activity, the agent simply switched to a different endpoint on the same host and carried on.
We observed more than 15 different user-agent strings across the victims:
Python-based clients and
curl;Truncated Chrome strings and headless browsers with seemingly random version numbers.
More distinctive, self-describing identifiers, such as
ReconProbe/1.0.
This variety, combined with the consistent attack patterns and ARTEX-related indicators, helped us connect the activity across multiple organizations.
Although most of these attempts failed, the true threat lies in the methodology. While a human attacker is bound by time constraints and fatigue, an autonomous agent does not give up. It simply continues to iterate until it finds a single weak point.
A clearly agentic attack
None of the individual techniques observed are novel. However, together the agent behind this attack is illuminated. There are a few clear signals:
Steps were chained automatically: when sign-up was open, it registered with a disposable mailbox, confirmed the account, and immediately requested another company's data.
Each automated step used the output of the last one: internal API routes are called by name minutes after pulling the source maps
Adaptation was automatic: when a login page started rate-limiting, the agent moved to a different endpoint on the same host. When an IP was blocked, a new one appeared within minutes.
Not all attacks were logical: a human attacker of this skill level is unlikely to spend their time testing generic payloads on the heavily scrutinized Microsoft OAuth flows.
Staying Ahead of AI-Powered Attacks
As AI makes reconnaissance and exploitation attempts faster and easier to scale, defenders need to shorten the gap between exposure and remediation. Learn more about how to prepare with Wiz's AI Threat Readiness Framework.
In addition, Wiz's AI Red Agent continuously and autonomously conducts offensive tests, helping reduce exposure at the speed of AI - evening the scales.
Wiz customers can refer to our Threat Intel Center Alert: ARTEX: Agentic AI Campaign Enables Cloud and Supply Chain Compromise
Existing detection rules can also effectively identify this activity, for example:
Numerous Failed Login Attempts To Multiple Users Followed By A Successful Login To Admin User
Potential Password Spray Attack From Single IP
Okta Users Password Spray
The relentless behavior also creates predictable patterns that can also be detected by rules such as "Unusual Mass Access Denied Activity."
Indicators of Compromise
Note: many of the provided user agents are not unique to this actor, and are expected to be noisy if hunted independently.
| Type | Indicator |
|---|---|
| IP Address | 104.194.150.21 |
| IP Address | 144.172.64.60 - Microsoft attributes to Storm-0940 |
| IP Address | 144.172.64.99 - Microsoft attributes to Storm-0940 |
| IP Address | 144.172.64.128 - Microsoft attributes to Storm-0940 |
| IP Address | 167.88.172.97 |
| User Agent | curl/7.88.1 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0 Safari/537.36 |
| User Agent | Python-urllib/3.12 |
| User Agent | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0 Safari/537.36 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0 |
| User Agent | Mozilla/5.0 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 |
| User Agent | python-requests/2.34.2 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0 Safari/537.36 |
| User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36 |
| User Agent | norma/0.4 |
| User Agent (Boto3 1.43.113) | Boto3/1.43.113 md/Botocore#1.43.113 ua/2.1 os/linux#6.8.0-147-generic md/arch#x86_64 lang/python#3.12.14 md/pyimpl#CPython m/e,b,Z,D cfg/retry-mode#legacy Botocore/1.43.113 |
| User Agent (Boto3 1.43.112) | Boto3/1.43.112 md/Botocore#1.43.112 ua/2.1 os/linux#6.8.0-147-generic md/arch#x86_64 lang/python#3.12.14 md/pyimpl#CPython m/n,Z,b,D cfg/retry-mode#legacy Botocore/1.43.112 |
| User Agent (aws-cli 1.46.1) | aws-cli/1.46.1 md/Botocore#1.43.62 ua/2.1 os/linux#6.8.0-147-generic md/arch#x86_64 lang/python#3.12.14 md/pyimpl#CPython m/b,Z,D cfg/retry-mode#legacy botocore/1.43.62 |
来源:Wiz:Research · wiz.io