move open esc close Searches the full text of every issue.

SOC Weekly Brief The week in the Microsoft security stack, distilled

8 obligations still ahead — the next falls on 1 Sep 2026. Every deadline →

  1. 1 Sep 2026, in 1 day. Passkeys become the default authentication method in Microsoft Entra ID. From this date, users enabled for SMS or voice...
  2. 7 Sep 2026, in 7 days. Self-service password reset stops accepting authentication methods that were never explicitly registered....
  3. 14 Sep 2026, in 14 days. the containerized data connector agent for the Microsoft Sentinel solution for SAP applications is permanently disabled...
  4. 30 Sep 2026, in 30 days. Entra Custom controls retire (end of life May 2027). Third-party MFA integrations wired through Custom controls must...
  5. 26 Oct 2026, in 56 days. Microsoft Entra ID is retiring custom CSS positioning properties in company-branded sign-in pages. As of 21 July 2026,...
  6. 27 Oct 2026, in 57 days. Microsoft Defender for Cloud stops enabling Foundational CSPM by default on new Azure subscriptions and moves it to an...
  7. 31 Mar 2027, in 212 days. Managing Microsoft Sentinel in the Azure portal is sunset (extended from 1 Jul 2026). Begin planning the move to the...
  8. 16 Aug 2027, in 350 days. the classic Defender for SQL APIs for Vulnerability Assessment and Advanced Threat Protection retire. Microsoft posted...

Latest issue · Week 35 · 13 min read

August 24 – August 31, 2026

What changed

Microsoft Threat Intelligence published a teardown of TerminalFix on 28 August, an eight-stage intrusion that starts with a fake Cloudflare CAPTCHA on a compromised website and ends with a reverse tunnel out of the network. The victim is talked into pasting a PowerShell command into Windows Terminal, which pulls a ZIP containing the legitimate LockScreenContentServer.exe alongside a malicious dui70.dll; the signed binary sideloads the DLL, which calls back out to PowerShell to fetch PNG images with executables hidden in the pixel data. Persistence is registry Run keys plus a scheduled task firing every 60 minutes. What follows is unusually patient: broad Active Directory enumeration covering domain trusts, admin group membership and server discovery, then an asynchronous command channel built on a file-watch loop that reads text files and passes their contents to Invoke-Expression, and finally a Python implant that opens a WebSocket tunnel to gitnow[.]dev on 443 and proxies TCP in SOCKS5 style. Antivirus coverage is Trojan:Win32/ClickFix., Trojan:Win32/TermFix., Trojan:Win32/Posilod.*, Trojan:Win64/DLLHijack.DAB!MTB and Trojan:Python/Indigo.SA, and Defender for Endpoint raises "An executable file loaded an unexpected DLL file", "Suspicious LDAP query", "Suspicious Active Directory enumeration" and "Possibly malicious use of proxy or tunneling tool" among others. Three advanced hunting queries ship with the post. The cheap preventive win is the same one that keeps coming up with ClickFix: configure Windows Terminal to warn on multi-line pastes, restrict the Run dialog and PowerShell through AppLocker or Application Control, and turn on script block logging. Treat any host that reached the tunnel stage as a pivot point and rotate the domain credentials it held. (Microsoft Security Blog)

Two days earlier, on 26 August, the same team published a survey of attacks against self-hosted AI infrastructure, and it is the most useful thing this week for anyone whose developers have stood up their own model gateway. The pattern across three products is identical: get in through an exposed control surface, read credentials out of the environment, persist, then mine. On LiteLLM the chain combined CVE-2026-42271, authenticated command execution in the MCP stdio endpoints, with CVE-2026-48710 in Starlette, a host-header validation bypass that weakens the authentication in front of it; from there attackers read /proc/1/environ for API keys, master keys and database connection strings, queried LiteLLM_ProxyModelTable and LiteLLM_VerificationToken in PostgreSQL directly, added SSH authorized keys and cron entries, and dropped XMRig with CPU tuning. RAGFlow was hit through a stack of template injection and path traversal issues (CVE-2026-45312, CVE-2026-28797, CVE-2026-24770 and CVE-2025-68700), with Python hooks injected into startup paths so that credentials were intercepted at the moment a user configured their LLM provider. Kestra fell to CVE-2026-49869, an authentication bypass that allowed unauthenticated workflow creation, from which the Docker socket exposed every container's Config.Env array. Defender alerts to know include "Suspicious shell execution from an AI workload process", "Suspicious process launched from a world-writable directory" and "Suspicious addition of an SSH key". The mitigation list is unglamorous and worth pushing: per-team virtual keys with spend limits instead of a shared master key, upstream API keys in a managed secret store rather than environment variables, databases behind private endpoints, deny-by-default egress, and Defender for Endpoint on Linux actually deployed on these hosts. (Microsoft Security Blog)

The Entra blog published a walkthrough on 25 August of something most teams assume they already have and do not: the ability to kill a service principal's access token on demand. Client credential flow tokens are bearer tokens with a 60 to 90 minute lifetime, and by default nothing you do — disabling the principal, rotating its secret, deleting it outright — stops that token from working until it expires. Continuous access evaluation changes that, but only if the client asked for it at authentication time by sending the xms_cc client capability claim with the value cp1. A CAE-enabled token looks different in two ways: it carries the claim, and its expiry runs roughly 24 hours after issue rather than 60 to 90 minutes, which reads as worse until you understand the trade — the longer lifetime is backed by three revocation events that invalidate it within minutes, namely the service principal being marked high risk, disabled, or deleted. The post's practical findings are the parts to carry into a runbook. Disabling the service principal is the faster and simpler kill switch, it produced an immediate 401, and it worked without a Workload Identity Premium licence; note that deactivating the registered application also disables the principal but does not fire the revocation event, so the action has to be taken on the service principal itself. The risk-based path needs pairing with a Conditional Access policy for workload identities that blocks authentication at high risk, otherwise an attacker holding the client ID and secret simply re-authenticates and gets a fresh token that no past revocation event touches. And the sting in the tail for anyone auditing their estate: you cannot retrofit this. Tokens issued without cp1 are not revocable, so the claim has to be set at integration time, which makes this a question to put to whoever owns your automation rather than something the SOC can switch on. Entra sign-in logs show "Continuous access evaluation Yes" on the Basic info tab where a token was CAE-enabled. (Microsoft Entra Blog)

Microsoft shipped an out-of-band Edge security release on 28 August, version 152.0.4191.53 on Chromium 152.0.7977.64/.65, and the volume is worth registering: 295 Chromium CVEs ingested in one release, plus nine Microsoft-specific entries across Edge, Edge for iOS and Copilot Chat in Edge. The one to prioritise is CVE-2026-72984, a type confusion remote code execution in Edge with a CVSS base score of 8.8, unauthenticated over the network with user interaction, and the only entry in the batch rated Exploitation More Likely — an attacker hosts a crafted page, convinces someone to open it, and executes code in the renderer. The rest are lower: CVE-2026-66324 spoofing at 6.5, CVE-2026-70309 a security feature bypass at 5.4, CVE-2026-62904 and CVE-2026-58616 information disclosure at 5.4 and 4.4, CVE-2026-70331 spoofing in Edge for iOS at 5.4, and two further remote code execution issues at 5.4 and 4.3. None is flagged as exploited or publicly disclosed. Edge updates itself, so for most estates this is a matter of confirming the fleet has moved rather than scheduling work — but a browser RCE marked more likely to be exploited is the kind of thing worth an actual compliance check against your device inventory rather than an assumption. (MSRC Security Update Guide)

Azure Bastion shareable link expiration reached general availability on 26 August. Shareable links let someone connect to a VM over RDP or SSH through Bastion without an Azure account or portal access, which has always made them the most quietly risky thing in the service: the link does not carry credentials, but it does carry indefinite reachability to a target resource, and nothing forced anyone to clean them up. You can now set an expiry date and time when creating the link, after which it stops connecting; the Shareable links page gains an Expiration column, expired links show a resource status of "Link expired", and you can filter on that status. Two things to do with this. Audit what you already have — a Bastion resource supports up to 500 shareable links, and long-lived ones created for a contractor or a one-off support session are exactly the kind of access nobody revisits. And check who can create them: by default users have Read access only, and creation and deletion are gated on specific Microsoft.Network/bastionHosts actions in IAM. (Azure Updates)

Two more Bastion changes landed the same day. Connecting to AKS clusters through Bastion went generally available: you tunnel from a local machine through Bastion to a private cluster's API server and use kubectl and the rest of the standard tooling, without exposing the endpoint publicly and without a jump box, VPN server or extra access agent to maintain. That is a genuine attack surface reduction if your current answer to "how do people reach the private cluster" is a long-lived bastion VM somebody patches occasionally. Separately, IPv6 dual stack support for Bastion entered public preview: a newly created deployment can carry both IPv4 and IPv6 public addresses, IPv6 covers the leg from the user to Bastion only, and connections from Bastion onward to target VMs stay IPv4. Existing IPv4-only deployments cannot be converted, so dual stack means building new. (Azure Updates)

Microsoft Purview's what's new page, dated 26 August, extends data protection to non-Microsoft SaaS. Both DLP policies and sensitivity label auto-labeling policies can now, in preview, protect data at rest in connected non-Microsoft applications such as Box and Google Workspace, running over the existing Defender for Cloud Apps connectors and using the same classification engine that covers Microsoft 365 locations. The practical read is that if you already have MDCA connectors wired up for those apps, the classification and labelling work you have done for SharePoint and OneDrive now reaches into them without a separate tool. The same update adds two things that make auto-labeling less of a leap of faith: simulation mode, which runs a policy and reports what it would have labelled without changing anything, and an Insights tab in the policy details panel showing match results and source distribution in both simulation and enforcement mode. (Microsoft Purview what's new)

The Defender for Endpoint what's new page picked up two Linux items this week. Antivirus audit mode for Linux entered preview: real-time malware detection and alerting with no quarantine and no process termination, which is the answer to the perennial objection from teams running sensitive or latency-critical Linux workloads who will not accept enforcement until they have seen what the product would have done. Use it to build the exclusion list and the performance case before you turn enforcement on. Offboarding API support for Linux went generally available, so Linux servers can be offboarded through the Offboard machine API rather than by hand — useful when ephemeral servers are the norm and stale devices are quietly inflating your inventory and your exposure score. Both need Defender for Endpoint on Linux version 101.26062.0007 or later. (Microsoft Defender for Endpoint what's new)

KQL to try

Two related Defender for Endpoint hunts from the same author, both keyed on a shared list of domain patterns that show up in tooling and exfiltration rather than in normal traffic: Burp Collaborator (oastify.com, portswigger.net), the whatismyip family, and generated-looking hostnames under CloudFront, KeyCDN, Azure Front Door, Azure cloudapp and AWS API Gateway. The first correlates network events with image load events on the same process, so it surfaces the loaded module behind the connection and filters on FileProfile prevalence and signature state to drop the common and the signed. (Multiple-Uncommon loaded image connection to suspicious domain — Jose Sebastián Canós)

let query_frequency = 1h;
let query_period = 14d;
let suspicious_domains = dynamic([
    @"d\d[a-z0-9]{12}\.cloudfront\.net",
    @"[\-\w]+\-[a-f0-9]{3,5}\.kxcdn\.com",
    @"[\-\w]+\-[a-z0-9]{16}\.\w\d\d\.azurefd\.net",
    @"[\-\w]+\.[a-z0-9]+\.cloudapp\.azure\.com",
    @"[a-z0-9]{10}\.execute\-api\.[a-z]{2}\-[a-z]+\-\d\.amazonaws\.com",
    @"portswigger\.net",
    @"oastify\.com",
    @"whatismyip\.com",
    @"whatismyip\.net",
    @"whatismyipaddress\.com"
]);
let excluded_urls = dynamic([
    "uhf-exp-fd-gbcrdgggfbggh0g3.b02.azurefd.net",
    "vs-exp-afd-prod-endpoint-e3b9a0c0h0e8d6fd.b02.azurefd.net"
]);
let excluded_company_names = dynamic([]);
let excluded_original_names = dynamic([]);
DeviceNetworkEvents
| where Timestamp > ago(query_period)
| where RemoteUrl matches regex strcat_array(suspicious_domains, "|") // and not(InitiatingProcessAccountSid in ("S-1-5-18", "S-1-5-20"))
//| where not(RemoteUrl has_any (excluded_urls))
| where not(InitiatingProcessUniqueId == 0)
| project DeviceId, DeviceName, LocalIP, ActionType, RemoteIP, RemotePort, RemoteUrl, Protocol, InitiatingProcessUniqueId
| as _AuxiliarEvents
| join kind=inner (
    DeviceImageLoadEvents
    | where Timestamp > ago(query_period)
    | where not(InitiatingProcessUniqueId == 0) and (isnotempty(SHA1) or isnotempty(SHA256) or isnotempty(MD5)) and DeviceId in (toscalar(_AuxiliarEvents | summarize make_set(DeviceId)))
    | project-away DeviceName, ActionType
    ) on DeviceId, InitiatingProcessUniqueId
| project-away DeviceId1, InitiatingProcessUniqueId1
| summarize
    StartTime = arg_min(Timestamp, *),
    EndTime = max(Timestamp),
    DeviceNamesSample = array_sort_asc(make_set(DeviceName, 100)),
    RemoteUrlsSample = array_sort_asc(make_set(RemoteUrl, 100))
    by SHA1, SHA256, MD5
| where StartTime > ago(query_frequency)
| invoke FileProfile("SHA1", 1000)
| where not(GlobalPrevalence > 10000)
| where not(GlobalPrevalence > 1000 and GlobalFirstSeen < ago(query_period))
| where not(GlobalPrevalence > 1000 and GlobalFirstSeen < ago(query_frequency) and SignatureState == "SignedValid")
| where not(GlobalPrevalence > 500 and InitiatingProcessVersionInfoCompanyName in (excluded_company_names) and InitiatingProcessVersionInfoOriginalFileName in (excluded_original_names))
| where not(GlobalFirstSeen < ago(5 * 365d))
| project
    StartTime,
    EndTime,
    DeviceNamesSample,
    RemoteUrlsSample,
    Timestamp = StartTime,
    DeviceId,
    DeviceName,
    LocalIP,
    ActionType,
    RemoteIP,
    RemotePort,
    RemoteUrl,
    Protocol,
    FileName,
    FolderPath,
    SHA1,
    SHA256,
    MD5,
    FileSize,
    GlobalPrevalence,
    GlobalFirstSeen,
    GlobalLastSeen,
    SignatureState,
    InitiatingProcessAccountName,
    InitiatingProcessAccountSid,
    InitiatingProcessAccountUpn,
    InitiatingProcessAccountObjectId,
    InitiatingProcessFileName,
    InitiatingProcessFolderPath,
    InitiatingProcessCommandLine,
    InitiatingProcessCreationTime,
    IsInitiatingProcessRemoteSession,
    InitiatingProcessParentFileName,
    InitiatingProcessVersionInfoCompanyName,
    InitiatingProcessVersionInfoProductName,
    InitiatingProcessVersionInfoOriginalFileName,
    InitiatingProcessVersionInfoInternalFileName,
    InitiatingProcessVersionInfoFileDescription,
    InitiatingProcessVersionInfoProductVersion,
    InitiatingProcessUniqueId,
    ReportId

The companion query drops the image load join and groups by the initiating process's version metadata instead, which makes it the lighter of the two and the better starting point if you want to see which uncommon binaries in your estate are reaching those domains at all. It was published on 24 August, a few days ahead of the one above. (DeviceNetworkEvents-Uncommon process connection to suspicious domain — Jose Sebastián Canós)

let query_frequency = 1h;
let query_period = 14d;
let suspicious_domains = dynamic([
    @"d\d[a-z0-9]{12}\.cloudfront\.net",
    @"[\-\w]+\-[a-f0-9]{3,5}\.kxcdn\.com",
    @"[\-\w]+\-[a-z0-9]{16}\.\w\d\d\.azurefd\.net",
    @"[\-\w]+\.[a-z0-9]+\.cloudapp\.azure\.com",
    @"[a-z0-9]{10}\.execute\-api\.[a-z]{2}\-[a-z]+\-\d\.amazonaws\.com",
    @"portswigger\.net",
    @"oastify\.com",
    @"whatismyip\.com",
    @"whatismyip\.net",
    @"whatismyipaddress\.com"
]);
let excluded_company_names = dynamic([]);
let excluded_original_names = dynamic([]);
DeviceNetworkEvents
| where Timestamp > ago(query_period)
| where RemoteUrl matches regex strcat_array(suspicious_domains, "|") // and not(InitiatingProcessAccountSid in ("S-1-5-18", "S-1-5-20"))
| where isnotempty(InitiatingProcessFileName)
| summarize
    StartTime = arg_min(Timestamp, *),
    EndTime = max(Timestamp),
    DeviceNamesSample = array_sort_asc(make_set(DeviceName, 100)),
    RemoteUrlsSample = array_sort_asc(make_set(RemoteUrl, 100))
    by InitiatingProcessVersionInfoCompanyName, InitiatingProcessVersionInfoProductName, InitiatingProcessVersionInfoOriginalFileName, InitiatingProcessVersionInfoInternalFileName, InitiatingProcessVersionInfoFileDescription
| where StartTime > ago(query_frequency)
| invoke FileProfile("InitiatingProcessSHA1", 1000)
| where not(GlobalPrevalence > 10000)
| where not(GlobalPrevalence > 1000 and GlobalFirstSeen < ago(query_frequency) and SignatureState == "SignedValid")
| where not(GlobalPrevalence > 500 and InitiatingProcessVersionInfoCompanyName in (excluded_company_names) and InitiatingProcessVersionInfoOriginalFileName in (excluded_original_names))
| project
    StartTime,
    EndTime,
    DeviceNamesSample,
    RemoteUrlsSample,
    Timestamp = StartTime,
    DeviceId,
    DeviceName,
    LocalIP,
    ActionType,
    RemoteIP,
    RemotePort,
    RemoteUrl,
    Protocol,
    InitiatingProcessAccountName,
    InitiatingProcessAccountSid,
    InitiatingProcessAccountUpn,
    InitiatingProcessAccountObjectId,
    InitiatingProcessSHA1,
    InitiatingProcessSHA256,
    InitiatingProcessMD5,
    InitiatingProcessFileName,
    InitiatingProcessFolderPath,
    InitiatingProcessCommandLine,
    InitiatingProcessCreationTime,
    IsInitiatingProcessRemoteSession,
    InitiatingProcessParentFileName,
    InitiatingProcessVersionInfoCompanyName,
    InitiatingProcessVersionInfoProductName,
    InitiatingProcessVersionInfoOriginalFileName,
    InitiatingProcessVersionInfoInternalFileName,
    InitiatingProcessVersionInfoFileDescription,
    InitiatingProcessVersionInfoProductVersion,
    GlobalPrevalence,
    GlobalFirstSeen,
    GlobalLastSeen,
    SignatureState,
    ReportId

Worth knowing

The August edition of the Microsoft Security roundup landed on 27 August, and most of it has already appeared in earlier issues — Defender Experts MDR Plan 2 covering third-party sources through Sentinel, Entra Tenant Governance reaching general availability, agentic containment guidance in Secure Now. Two items had not. Purview auto-labeling policies now process up to 500,000 SharePoint and OneDrive files a day, up from 100,000, which matters if you have been throttling a rollout to fit the old ceiling. And Intune's unattended support with remote sign-in went generally available, letting IT sign in to a device without the user present, with role-based permissions, compliance checks and session auditing built in. That last one deserves a second look given that two Remote Help vulnerabilities were disclosed a week earlier, including a search-path weakness rated 7.1: helpdesk tooling that can reach an endpoint without a human at the other end is a high-value target, and the session auditing is the control you will want configured before anyone uses it in anger. (Microsoft Security Blog)

Igor Sakhnov, who runs Azure Networking, published an argument on 25 August that is worth reading if you are the person who has to explain patching timelines to leadership. The premise is that the gap between disclosure and exploitation has collapsed to hours while enterprise patch validation and deployment still takes days or weeks, so a vulnerability management programme built entirely on getting the patch out is structurally behind. His proposed complement is network-level enforcement — controls that can be changed far faster than software can be validated and shipped, used to restrict access and contain lateral movement during the window when the fix exists but is not everywhere yet. It is a vendor argument for Defender for Cloud and virtual network controls, and it is also a fair description of what a good incident response actually looks like. If you have ever had to answer "what are we doing about this until the patch lands", this is the framing for that conversation. (Azure Blog)