At a glance: fixes and indicators
Written for organizations and the teams who defend them. IoC = evidence it already happened (an address, an account, a log line). IoA = the behavior of an attack in progress. Network IoCs are defanged: remove the square brackets before using them. Indicators age fast, so re-check the source before blocking.
| Item | Exploited? · Fix | Do now | Top IoCs | Top IoAs |
|---|---|---|---|---|
| 1. Atlassian CVE-2026-21589 | Not reported, per Atlassian · fixed builds per product (listed in item) | Update; apply Atlassian's request-filter rule meanwhile; run the log hunt | None published | Request lines that, after URL-decoding, contain .. next to /, \ or :: |
| 2. Exchange CVE-2026-96940 | Not known, per Microsoft · October 2026 out-of-band update (KB5129958 for 2016 CU23) | Install on every Exchange server and every machine with Exchange Management Tools; check audit logs | None published | Mailbox access by an account to a mailbox that is not its own (ours) |
| 3. MALFEX npm campaign | Yes, packages delivered malware, per CloudSEK · no patch; remove packages | Search lockfiles and caches for the named packages; check Windows hosts for the artifacts | AutoIt3.exe under a ScopeSmart Technologies Inc folder; scheduled task Maiden; 104.234.65[.]75:700 |
npm install scripts that download an executable disguised as a PNG |
Highest payoff today — analysis. One search of web access logs for URL-decoded .. sequences next to path separators. It uses Atlassian's own detection guidance, takes minutes, and also answers whether anyone has already probed the flaw.
How to use this. A published-IoC hit means compromise: handle it under the item's defined response. An IoA hit alone is a lead to validate (PIVCCERL™'s Validation stage). An empty IoC row is not reassurance: for the Atlassian and Exchange flaws nothing has been published, and a quiet read-only request may leave little behind. The hunt packs say what to do on a hit and what a clean result means.
1. Atlassian: one flaw, eight products, and a request filter you can add today
Bottom line. Atlassian published CVE-2026-21589 on 5 October: an unauthenticated visitor can read specific files inside the web application root, provided they know the file's exact name and path. They cannot list directories. It is rated CVSS 4.0 9.3, and Atlassian says its "investigation has not found evidence of exploitation." Fixed builds exist for every affected product. Do now: list every Atlassian Data Center instance, Crucible and Fisheye, update, and apply Atlassian's request-filter rule where you cannot update today. Skip if: you use none of Bitbucket, Confluence, Jira, Jira Service Management, Bamboo or Crowd Data Center, Crucible or Fisheye. Atlassian's advisory says affected Atlassian Cloud products have already been patched.
Indicators
| Type | Indicator | Where to look | Source |
|---|---|---|---|
| IoC | None published — no exploitation reported | — | Atlassian advisory, 5 Oct 2026 |
| IoA | A request line that, after URL-decoding (up to two passes), contains .. immediately next to /, \ or :: |
Web server, application and reverse-proxy access logs | Atlassian advisory, 5 Oct 2026 |
| IoA | A request from outside your network for a file path that no page on your instance links to | Access logs, WAF logs | Ours |
What
Per Atlassian's advisory, the flaw affects all versions earlier than the fixed ones. Fixed versions: Bitbucket Data Center 9.4.26, 10.2.8 and 10.5.1; Confluence Data Center 9.2.26 and 10.2.19; Jira Software Data Center 9.12.40, 10.3.26 and 11.3.12; Jira Service Management Data Center 5.12.40, 10.3.26 and 11.3.12; Bamboo Data Center 10.2.24 and 12.1.12; Crowd Data Center 6.3.7, 7.0.3, 7.1.7 and 7.2.4; Crucible and Fisheye 4.9.15. Mitigations: a web application firewall rule blocking .. adjacent to /, \ or ::; enabling Tomcat's RewriteValve through server.xml and a rewrite.config file (Confluence, Jira, Jira Service Management, Bamboo, Crowd); or a rule in urlrewrite.xml (Bitbucket only). No researcher is credited. Where sources differ: the CVE record as we read it lists Bamboo 10.2.4 and Crowd 7.1.1, and also lists Server editions as affected without a fix, where Atlassian's advisory and The Hacker News give 10.2.24 and 7.1.7 for Data Center. We plan on Atlassian's advisory for Data Center, and on the CVE record's wider list for scoping: if you still run a Server edition, treat it as affected with no patch and move the control to the request filter and to retirement. The flaw is not in CISA's Known Exploited Vulnerabilities catalog (version 2026.10.04).
So what
A critical rating on a flaw that can only read files you already know the path to is a narrower hole than it first sounds, and Atlassian says it has seen no exploitation. Two things still make it worth acting on: it needs no sign-in, and what it exposes depends on what sits under your web root, which only you can check. These platforms often hold source code, tickets and credentials, and are often reachable from outside the network. Public advisories on widely deployed products tend to draw scanning quickly (our reading, not a sourced claim).
Now what — P (Preparation); P → I for any instance that was reachable from the internet; analysis
- Configuration. Update each product to its fixed build above. Where that needs a window, apply Atlassian's WAF regex or Tomcat rewrite rule now, and confirm it by sending a request containing an encoded
..%2fsequence to a test instance. - Blast radius. Take management and administration paths off the public internet or behind a VPN or allow-list. Check what files exist under each application's web root, and keep credentials and backups out of it.
- Detection with a defined response. Run the hunt pack below over the last several weeks of access logs. Defined response: a hit that returned a success status for a real file is a confirmed read: identify the file, rotate anything it held, preserve the logs, and review what else that source address requested. Hits that returned errors are attempts: block the source and move on to the update.
- Communication. Tell the owners of the Atlassian tools, who are often teams outside IT, that an update window is coming. If a file holding customer or employee data was read, your legal and privacy contacts decide on notification.
Hunt pack — run it, then act on what it says
These hunts implement Atlassian's own detection method: URL-decode each request line (up to two passes), then look for .. immediately next to /, \ or ::. They are our analysis of that method. The bash script was run against synthetic logs (clean, hit, empty and compressed inputs); the Sigma rule was parsed and converted to Splunk, Kusto and Lucene queries with pySigma; the other languages were reviewed, not executed against a live platform, so test them on a non-production index first. Adjust field and table names to your logging.
#!/usr/bin/env bash
# Usage: ./atlassian-hunt.sh /path/to/access.log* (plain or .gz)
set -euo pipefail
[ $# -ge 1 ] || { echo "usage: $0 LOGFILE..." >&2; exit 2; }
zcat -f -- "$@" | python3 -c '
import re, sys
from urllib.parse import unquote
pat = re.compile(r"\.\.[/\\]|[/\\]\.\.|\.\.::|::\.\.") # ".." next to / \ or ::
lines = hits = 0
for n, raw in enumerate(sys.stdin, 1):
lines += 1
d = raw
for _ in range(2): # up to two URL-decode passes
d = unquote(d)
if pat.search(d):
hits += 1
print(f"{n}: {raw.rstrip()[:300]}")
print(f"scanned={lines} hits={hits}", file=sys.stderr)
sys.exit(3 if lines == 0 else (1 if hits else 0))
'
# Usage: .\atlassian-hunt.ps1 -Path 'D:\logs\access*.log'
param([Parameter(Mandatory)][string]$Path)
$files = Get-ChildItem -Path $Path -File -ErrorAction Stop
if (-not $files) { Write-Error 'No log files matched - this is NOT a clean result'; exit 3 }
$pat = '\.\.[/\\]|[/\\]\.\.|\.\.::|::\.\.'
$lines = 0; $hits = 0
foreach ($f in $files) {
Get-Content -LiteralPath $f.FullName | ForEach-Object {
$lines++
$d = $_
foreach ($i in 1..2) { try { $d = [uri]::UnescapeDataString($d) } catch { } }
if ($d -match $pat) { $hits++; '{0}: {1}' -f $f.Name, $_.Substring(0, [Math]::Min(300, $_.Length)) }
}
}
Write-Host "scanned=$lines hits=$hits"
if ($lines -eq 0) { exit 3 } elseif ($hits -gt 0) { exit 1 } else { exit 0 }
title: CVE-2026-21589 path traversal attempt (Atlassian Data Center, Crucible, Fisheye)
id: 7349ecbd-c4ca-4f05-8fea-f8d33c9ecf96
status: experimental
description: Request URI containing a traversal sequence, plain or percent-encoded, per the detection method in Atlassian's advisory for CVE-2026-21589.
references:
- https://confluence.atlassian.com/security/cve-2026-21589-arbitrary-file-access-vulnerability-impacts-multiple-products-1870495748.html
author: Threat Vector Management
date: 2026-10-06
tags:
- attack.initial_access
- attack.t1190
logsource:
category: webserver
detection:
selection:
c-uri|contains:
- '../'
- '/..'
- '..%2f'
- '..%5c'
- '%2e%2e'
- '..%252f'
- '%252e%252e'
condition: selection
falsepositives:
- Vulnerability scanners you run; legitimate URLs containing three dots
level: high
index=* (sourcetype=access_combined OR sourcetype=iis OR sourcetype=*tomcat* OR sourcetype=*proxy*) earliest=-30d
| eval decoded=urldecode(urldecode(_raw))
| where match(decoded, "\.\.[/\\\\]") OR match(decoded, "[/\\\\]\.\.") OR match(decoded, "\.\.::") OR match(decoded, "::\.\.")
| stats count min(_time) AS first max(_time) AS last values(status) AS statuses BY src_ip, host
W3CIISLog
| where TimeGenerated > ago(30d)
| extend d = url_decode(url_decode(strcat(csUriStem, "?", csUriQuery)))
| where d matches regex @"\.\.[/\\]|[/\\]\.\.|\.\.::|::\.\."
| summarize hits = count(), first = min(TimeGenerated), last = max(TimeGenerated), statuses = make_set(scStatus) by cIP, Computer
FROM logs-*
| WHERE @timestamp > NOW() - 30 days
| WHERE url.original LIKE "*../*" OR url.original LIKE "*/..*" OR TO_LOWER(url.original) LIKE "*..%2f*" OR TO_LOWER(url.original) LIKE "*..%5c*" OR TO_LOWER(url.original) LIKE "*%2e%2e*"
| STATS hits = COUNT(*), first = MIN(@timestamp), last = MAX(@timestamp) BY source.ip, host.name
alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"TVM CVE-2026-21589 encoded traversal in URI"; flow:established,to_server; http.uri.raw; content:"%2e%2e"; nocase; classtype:web-application-attack; sid:9002101; rev:1;)
alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"TVM CVE-2026-21589 plain traversal in URI"; flow:established,to_server; http.uri.raw; content:"../"; classtype:web-application-attack; sid:9002102; rev:1;)
| If you see | Do this |
|---|---|
| A hit with a 2xx status on a path that is not a normal page | Treat as a confirmed file read. Identify the file, rotate anything it held, preserve the logs, and search every log for the same source address. |
| Hits that all returned 4xx or 5xx | Treat as attempts. Block the source, update, and keep the logs; re-run the hunt after the update to confirm the filter works. |
| A hit from a scanner you operate | Confirm with its owner, record it, and exclude that source next time. |
| One source hitting several Atlassian products | Treat as a sweep. Block it, hunt that address in all other logs, and check non-Atlassian applications behind the same proxy. |
| The script exits 3 or the query returns no rows because no logs exist | This is not a clean result. Find where the logs went, and rely on the update and the request filter instead. |
| No hits | A good sign, not an exoneration. Logs rotate, a reverse proxy may normalize or drop a request before it is logged, and the query only finds what it was written to find. Update and filter anyway. |
2. Exchange: an out-of-band update for a signed-in user reading other people's mail
Bottom line. Microsoft released an out-of-band update for CVE-2026-96940 in Exchange Server. An authenticated user can reach other users' email and attachments within the same organization; it cannot cross tenants. The CVE record rates it CVSS 3.1 8.8. Help Net Security reports that Microsoft is "not aware of active exploitation" and that the Exchange Online service was fixed on Microsoft's side in late September. Do now: install the update on every Exchange server and on every workstation that has the Exchange Management Tools, then run the audit-log hunt. Skip if: you use Exchange Online only with no on-premises Exchange servers or management-tools installs, or a mail platform that is not Exchange.
Indicators
| Type | Indicator | Where to look | Source |
|---|---|---|---|
| IoC | None published — Microsoft reports no known exploitation | — | Microsoft CVE record; Help Net Security, 5 Oct 2026 |
| IoA | An account opening mail or attachments in a mailbox it has no delegation for | Exchange mailbox audit logs, where auditing is enabled | Ours |
What
The CVE record, published 2 October and updated 3 October, calls it an "Exchange Server Elevation of Privilege Vulnerability" and lists Exchange Server 2016 CU23, 2019 CU14 and CU15, and Subscription Edition RTM. Microsoft's support page KB5129958, dated 2 October, describes version 2 of the security update for Exchange 2016 CU23, replacing KB5121576 from 11 August, and lists CVE-2026-96940 with eight other CVEs. It says 2016 updates go to organizations enrolled in the Period 2 Extended Security Update program, with eligibility running until the end of October 2026. Help Net Security's article is dated 5 October, describes the same release as the "September 2026 v2" update, and reports that the flaw was discovered internally at Microsoft. We did not verify the fixed build numbers for the other versions: the CVE record's fixed-build column equals the top of its vulnerable range. We are not quoting build numbers; check the KB for your version.
So what
Mailbox contents are what an attacker wants after stealing any ordinary account, and this flaw turns one ordinary account into access to many. Microsoft's own position is "not exploited," which is a statement about today. The prudent order is to treat the update as a priority patch rather than a watch item, because Help Net Security notes that this type of flaw has been exploited in the past.
Now what — P (Preparation); analysis
- Configuration. Install the October update for your version on every server and on workstations with Exchange Management Tools, then run Microsoft's Exchange Health Checker to confirm. Organizations on Exchange 2016 outside the ESU program have no update path from this release: plan the move to Subscription Edition.
- Blast radius. Review which service accounts and shared accounts can sign in to mailboxes, remove stale accounts, and require multi-factor authentication for every user so that a stolen password is not enough to reach this flaw.
- Detection with a defined response. Run the hunt pack below. Defined response: one unexplained non-owner access is a lead to validate (confirm with the account owner); a pattern across many mailboxes from one account is compromise: disable the account, reset its credentials and sessions, preserve audit logs, and scope what was read.
- Communication. If you run both Exchange Online and on-premises servers, say which of the two this applies to when you tell management: the cloud service was already fixed by Microsoft.
Hunt pack — run it, then act on what it says
No source has published a request pattern, process or file for this flaw, so the hunts here check patch state and look for access to mailboxes by accounts that do not own them. That is our analysis, not a published indicator. We are not offering a Sigma, Suricata or YARA rule for this item: a rule written from a guess would be counted as a control it is not. Reviewed, not executed against a live platform; test on a non-production system first.
# 1) Patch state: compare each AdminDisplayVersion with the build in the KB for that server's version.
Get-ExchangeServer | Sort-Object Name | Format-Table Name, ServerRole, AdminDisplayVersion -AutoSize
# 2) Is mailbox auditing on? If this prints True, an empty result below means NOTHING.
if ((Get-OrganizationConfig).AuditDisabled) { Write-Warning 'Mailbox auditing is DISABLED: results below are not a clean result' }
# 3) Non-owner access, last 30 days (heavy on large estates: start with high-value mailboxes)
$start = (Get-Date).AddDays(-30)
$rows = foreach ($m in Get-Mailbox -ResultSize Unlimited) {
Search-MailboxAuditLog -Identity $m.Identity -LogonTypes Delegate,Admin -StartDate $start -ShowDetails -ResultSize 1000 -ErrorAction SilentlyContinue |
Select-Object @{n='Mailbox';e={$m.PrimarySmtpAddress}}, LogonUserDisplayName, Operation, LastAccessed, ClientIPAddress, ClientInfoString
}
if (-not $rows) { 'No non-owner access entries found (see the table: not an exoneration).' }
else { $rows | Sort-Object LastAccessed | Export-Csv .\nonowner-access.csv -NoTypeInformation; "$(@($rows).Count) rows written to nonowner-access.csv" }
OfficeActivity
| where TimeGenerated > ago(30d) and OfficeWorkload == "Exchange"
| where Operation in ("MailItemsAccessed", "Update", "MoveToDeletedItems", "SoftDelete", "HardDelete")
| where Logon_Type in ("Delegate", "Admin") and tolower(MailboxOwnerUPN) != tolower(UserId)
| summarize actions = count(), mailboxes = dcount(MailboxOwnerUPN), first = min(TimeGenerated), last = max(TimeGenerated) by UserId, ClientIP
| order by mailboxes desc
index=o365 sourcetype="o365:management:activity" Workload=Exchange Operation=MailItemsAccessed earliest=-30d
| where lower(MailboxOwnerUPN)!=lower(UserId) AND (LogonType=1 OR LogonType=2)
| stats count dc(MailboxOwnerUPN) AS mailboxes min(_time) AS first max(_time) AS last BY UserId, ClientIPAddress
| sort - mailboxes
| If you see | Do this |
|---|---|
| A server whose version is below the fixed build in the KB | Treat as exposed to any signed-in user. Patch now, and run the audit hunt for the period it was exposed. |
| One account reading many mailboxes it has no delegation for | Treat as compromise. Disable the account, reset credentials and sessions, preserve audit logs, scope what was read, and bring in privacy and legal contacts. |
| Access by eDiscovery, backup, journaling or other service accounts | Record each as expected, document the owner, and exclude it next time. |
| An empty result because auditing is disabled or logs were not kept | This is not a clean result. Turn auditing on now and rely on the patch. |
| No non-owner access found | A good sign, not an exoneration. A flaw that bypasses an authorization check may not be recorded as delegate or admin access at all (our reading), and audit logs only go back as far as you keep them. Patch anyway. |
3. MALFEX: an npm campaign that kept three packages installable for fourteen months
Bottom line. CloudSEK's 30 September analysis describes MALFEX, an npm campaign that used install scripts to download a Windows executable disguised as a PNG file. One branch installs a remote-access trojan; another installs a Node.js stealer aimed at Discord clients, browser data, Telegram sessions and cryptocurrency wallets. SecurityWeek reported on 6 October that the campaign has accumulated more than 40,000 downloads. CloudSEK counts eight malicious packages, five with advisories and three without. Do now: search lockfiles, caches and build logs for the package names below, and check Windows developer and build hosts for the persistence artifacts. Skip if: nobody in your organization installs npm packages, or only on macOS or Linux, where SecurityWeek reports the malware fails silently.
Indicators
| Type | Indicator | Where to look | Source |
|---|---|---|---|
| IoC | Package names function-flag, function-color, cdn-img-fetch, tlxbnhd, tldriver, mxdriver, img-to-native |
package.json, lockfiles, npm cache, build logs |
CloudSEK, 30 Sep 2026 |
| IoC | npm publisher accounts malfexkkj, malfex_user, malfexteste2, malfexteste3, malfexteste4; GitHub account cavecrew |
Registry metadata, repository history | CloudSEK, 30 Sep 2026 |
| IoC | %LOCALAPPDATA%\ScopeSmart Technologies Inc\AutoIt3.exe; scheduled task Maiden; gldriver_pre_core.exe, gldriver_pre_asset.exe |
Windows endpoints, EDR | CloudSEK, 30 Sep 2026 |
| IoC | 104.234.65[.]75:700; api.imghippo[.]com; an attacker-controlled Discord webhook (address not published) |
Proxy, DNS and flow logs | CloudSEK, 30 Sep 2026 |
| IoA | An install script that downloads an executable named as a .png file, then runs an AutoIt interpreter from a user-profile folder |
Process lineage on developer and build hosts | CloudSEK, 30 Sep 2026 |
| IoA | A Node.js process of roughly 64 MB started by an installed dependency, touching Discord client folders or browser profiles | EDR file and process telemetry | CloudSEK, 30 Sep 2026 |
What
Per CloudSEK, the campaign's function-flag package was malicious from 18 July 2025, function-color is a wrapper that pulls it in as a dependency, and cdn-img-fetch remained installable after its parent package was removed. tlxbnhd, tldriver, mxdriver and img-to-native are described as advised (flagged) packages. One branch extracts a signed AutoIt interpreter and runs an encrypted script that starts a Go-based remote-access client, with a Solana-blockchain lookup to find its control server; the other fetches a PNG polyglot from GitHub and a 64 MB Node.js bundle named movinlike that injects Discord clients and takes browser and Telegram data. CloudSEK cites an Amazon Inspector entry, MAL-2026-17216, issued 28 September for img-to-native. SecurityWeek (6 October) gives the figure of more than 40,000 downloads. Hackread's coverage speaks of at least 12 packages. We plan on CloudSEK's count: its report says twelve were uploaded, eight are malicious and four are benign cover. Two limits: in the text we read, CloudSEK names seven of the eight malicious packages (the lists here use those seven), and none of the sources we read gave version numbers.
So what
A developer workstation or build runner holds source code, signing material and cloud credentials, so a remote-access trojan or stealer there is a way into much more than one machine. This campaign targeted whoever installed the packages, with no named organization (SecurityWeek). The lesson that outlasts it: a package's removal does not remove packages that depend on it, and a package with no advisory is not a package that has been checked.
Now what — P (Preparation); P → I where any listed package or artifact is found; analysis
- Configuration. Block the seven package names in your registry proxy or dependency policy. Where you can, set npm to refuse install scripts by default (
ignore-scripts) on build runners, and restrict outbound connections from them to what builds need. - Blast radius. Keep developer and build credentials short-lived and scoped, and keep long-lived tokens out of workstation profiles. Confirm that browser-stored passwords and wallet files are not on build hosts.
- Detection with a defined response. Run the hunt pack below. Defined response: a package name in a lockfile with no execution evidence means remove it and rebuild. Any persistence artifact or connection to the listed hosts is a confirmed compromise: isolate the machine, rotate every credential, token and session that user or runner held (including Discord, browser-saved logins and cloud keys), rebuild from clean media, and check what that host pushed to your repositories.
- Communication. Tell developers which packages to look for and why; ask them to report rather than quietly remove. If a build host shipped software while infected, your release owner decides whether customers need to hear.
Hunt pack — run it, then act on what it says
The indicators below are CloudSEK's, published 30 September; the queries are our analysis of how to find them. The bash script was run against synthetic manifests (hit, clean, look-alike name and empty inputs); the Sigma rules were parsed and converted to Splunk, Kusto and Lucene queries with pySigma; the other languages were reviewed, not executed against a live platform, so test them on a non-production system first. Defanged values in the code (a dot wrapped in square brackets) must have the brackets removed before use; the scripts that run as-is do it for you.
#!/usr/bin/env bash
# Usage: ./malfex-hunt.sh DIR...
set -uo pipefail
[ $# -ge 1 ] || { echo "usage: $0 DIR..." >&2; exit 2; }
NAMES='function-flag|function-color|cdn-img-fetch|tlxbnhd|tldriver|mxdriver|img-to-native'
hits=0; files=0
while IFS= read -r -d '' f; do
files=$((files+1))
if grep -EHn "(^|[/\"'[:space:]@])(${NAMES})(@|[\"':[:space:]]|$)" -- "$f" 2>/dev/null; then hits=$((hits+1)); fi
done < <(find "$@" -type f \( -name package.json -o -name package-lock.json -o -name npm-shrinkwrap.json \
-o -name yarn.lock -o -name pnpm-lock.yaml -o -name bun.lock \) -not -path '*/node_modules/*/node_modules/*' -print0 2>/dev/null)
while IFS= read -r d; do echo "INSTALLED: $d"; hits=$((hits+1)); done < <(
find "$@" -type d -path '*/node_modules/*' \( -name function-flag -o -name function-color -o -name cdn-img-fetch \
-o -name tlxbnhd -o -name tldriver -o -name mxdriver -o -name img-to-native \) 2>/dev/null)
echo "manifests_scanned=${files} hits=${hits}" >&2
[ "$files" -eq 0 ] && exit 3
[ "$hits" -gt 0 ] && exit 1
exit 0
$ip = '104[.]234[.]65[.]75' -replace '[\[\]]','' # refang at run time
$found = @()
Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue | ForEach-Object {
$p = Join-Path $_.FullName 'AppData\Local\ScopeSmart Technologies Inc'
if (Test-Path -LiteralPath $p) { $found += "FOLDER $p" }
}
Get-ScheduledTask -ErrorAction SilentlyContinue | Where-Object { $_.TaskName -eq 'Maiden' } |
ForEach-Object { $found += "TASK $($_.TaskPath)$($_.TaskName)" }
Get-ChildItem 'C:\Users' -Recurse -File -Include 'gldriver_pre_core.exe','gldriver_pre_asset.exe' -ErrorAction SilentlyContinue |
ForEach-Object { $found += "FILE $($_.FullName)" }
Get-NetTCPConnection -RemoteAddress $ip -RemotePort 700 -ErrorAction SilentlyContinue |
ForEach-Object { $found += "CONN local port $($_.LocalPort) to ${ip}:700, pid $($_.OwningProcess)" }
$found
if ($found.Count -gt 0) { exit 1 } else { 'No MALFEX artifacts found on this host (a good sign, not an exoneration).'; exit 0 }
title: MALFEX AutoIt interpreter running from the ScopeSmart folder
id: dfa64271-b1c0-4be0-92c3-27a5f829585f
status: experimental
description: Process image path reported by CloudSEK (30 Sep 2026) for the MALFEX remote-access chain.
author: Threat Vector Management
date: 2026-10-06
tags: [attack.execution, attack.persistence]
logsource: {category: process_creation, product: windows}
detection:
selection:
Image|endswith: '\ScopeSmart Technologies Inc\AutoIt3.exe'
condition: selection
level: high
---
title: MALFEX dropped executables
id: fc307d4f-7d7c-4430-b47b-d1be042d095f
status: experimental
description: File names reported by CloudSEK (30 Sep 2026).
author: Threat Vector Management
date: 2026-10-06
logsource: {category: file_event, product: windows}
detection:
selection:
TargetFilename|endswith:
- '\gldriver_pre_core.exe'
- '\gldriver_pre_asset.exe'
condition: selection
level: high
---
title: MALFEX scheduled task Maiden
id: 4e6e4a19-5c50-4893-a2d9-26053a400e7b
status: experimental
description: Task name reported by CloudSEK (30 Sep 2026). Security event 4698 requires task auditing.
author: Threat Vector Management
date: 2026-10-06
logsource: {product: windows, service: security}
detection:
selection:
EventID: 4698
TaskName: '\Maiden'
condition: selection
level: high
---
title: MALFEX payload host connection
id: 37cb5aec-a4dd-4ed8-825b-6d2cdf1d314d
status: experimental
description: Address and port reported by CloudSEK (30 Sep 2026) as serving the Node.js bundle.
author: Threat Vector Management
date: 2026-10-06
logsource: {category: network_connection, product: windows}
detection:
selection:
DestinationIp: '104.234.65[.]75' # remove the brackets
DestinationPort: 700
condition: selection
level: high
index=* source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" earliest=-30d
((EventCode=1 Image="*\\ScopeSmart Technologies Inc\\AutoIt3.exe")
OR (EventCode=11 (TargetFilename="*\\gldriver_pre_core.exe" OR TargetFilename="*\\gldriver_pre_asset.exe"))
OR (EventCode=3 DestinationIp="104.234.65[.]75" DestinationPort=700))
| stats count min(_time) AS first max(_time) AS last values(EventCode) AS codes BY host, User, Image
let ip = replace_string(replace_string("104[.]234[.]65[.]75", "[", ""), "]", "");
union
(DeviceProcessEvents | where Timestamp > ago(30d) and FolderPath endswith @"\ScopeSmart Technologies Inc\AutoIt3.exe"
| project Timestamp, DeviceName, Account = AccountName, What = "process", Detail = FolderPath),
(DeviceFileEvents | where Timestamp > ago(30d) and FileName in~ ("gldriver_pre_core.exe", "gldriver_pre_asset.exe")
| project Timestamp, DeviceName, Account = InitiatingProcessAccountName, What = "file", Detail = FolderPath),
(DeviceNetworkEvents | where Timestamp > ago(30d) and RemoteIP == ip and RemotePort == 700
| project Timestamp, DeviceName, Account = InitiatingProcessAccountName, What = "network", Detail = strcat(RemoteIP, ":700")),
(DeviceEvents | where Timestamp > ago(30d) and ActionType == "ScheduledTaskCreated" and AdditionalFields has "Maiden"
| project Timestamp, DeviceName, Account = InitiatingProcessAccountName, What = "task", Detail = AdditionalFields)
| sort by Timestamp desc
FROM logs-endpoint.events.*
| WHERE @timestamp > NOW() - 30 days
| WHERE process.executable LIKE "*\\ScopeSmart Technologies Inc\\AutoIt3.exe"
OR file.name IN ("gldriver_pre_core.exe", "gldriver_pre_asset.exe")
OR (destination.ip == "104.234.65[.]75" AND destination.port == 700)
| KEEP @timestamp, host.name, user.name, event.category, process.executable, file.path, destination.ip
| SORT @timestamp DESC
SELECT path, size, mtime FROM file WHERE path LIKE 'C:\Users\%\AppData\Local\ScopeSmart Technologies Inc\%';
SELECT name, path, action, enabled FROM scheduled_tasks WHERE name = 'Maiden' OR name LIKE '%\Maiden';
SELECT pid, path, remote_address, remote_port FROM process_open_sockets
WHERE remote_port = 700 AND remote_address = '104[.]234[.]65[.]75'; -- remove the brackets
alert tcp $HOME_NET any -> 104.234.65[.]75 700 (msg:"TVM MALFEX payload host (CloudSEK 2026-09-30)"; flow:to_server; classtype:trojan-activity; sid:9002201; rev:1;)
alert dns $HOME_NET any -> any any (msg:"TVM MALFEX image-host lookup, LOW FIDELITY: legitimate users may share it"; dns.query; content:"api.imghippo[.]com"; nocase; classtype:misc-activity; sid:9002202; rev:1;)
| If you see | Do this |
|---|---|
| A package name in a lockfile or manifest, with no installed copy and no execution evidence | Remove it, rebuild from a clean lockfile, and check CI logs for any Windows runner that ran npm install with scripts enabled. |
| An installed copy, or an install that ran on a Windows host | Treat the host as compromised. Isolate it, rotate every credential and token it held, rebuild from clean media, and review what it pushed to your repositories. |
The folder, the Maiden task, a dropped file or a connection to the payload host |
Confirmed compromise. Same response as above, and preserve the host image first. |
| An install on macOS or Linux only | Remove it and rebuild. SecurityWeek reports the malware fails silently there; rotate any token that was in the environment during the install unless you can show it was not. |
| A lookup of the image-host domain and nothing else | Low fidelity, because a legitimate service may share it. Check the process that made the request before acting. |
| The script exits 3 because no manifests were found | This is not a clean result. Point it at the right directories. |
| No hits | A good sign, not an exoneration. The hunts cover the seven names and artifacts CloudSEK published, not the eighth package or any later variant; cleaned workspaces and rotated caches erase evidence; and a registry takedown can leave nothing to find on hosts that were already infected. Block the names and tighten install scripts anyway. |
Sector signal — only what a source actually said
No source in this window attributed the Atlassian, Exchange or MALFEX items to a sector; absence of sector-attributable reporting is not absence of risk.
How this brief is put together
Facts are reported as their named source published them: versions and mitigations from Atlassian's advisory, CVE records and Microsoft's update notes, and indicators from CloudSEK's analysis. Where sources differ — Atlassian's fixed builds for Bamboo and Crowd, the date and naming of Microsoft's Exchange update, and the number of MALFEX packages — we say which reading we plan on. IoCs appear only as a named source published them and are defanged; IoAs are cited or marked ours. The hunt packs are our analysis of those sources: the same logic written for several platforms, so you can use the one you run. What was tested and what was only reviewed is stated in each pack. PIVCCERL™ is Threat Vector Management's incident lifecycle — Preparation, Identification, Validation, Containment, Communication, Eradication, Recovery, Lessons Learned; an unaffected organization is in Preparation, and a second stage appears where a hunt is warranted. ATT&CK: the one mapping shown, in the Atlassian Sigma rule, is ours; no source in this window published technique mappings. This brief publishes when something warrants it, not on a schedule.
Threat Vector Management helps organizations and the MDR and SOC teams that defend them turn briefs like this into action — running a look-back hunt across the logs you already keep, and deciding what a clean result does and does not let you close. Start a conversation →
More editions: Threat Brief archive.
Threat Vector Management is not affiliated with any company operating under the name “ThreatVector.”
Sources
- Atlassian — Security advisory for CVE-2026-21589, 5 Oct 2026
- CVE record — CVE-2026-21589
- The Hacker News — Critical Atlassian flaw lets unauthenticated attackers read known files, 6 Oct 2026
- CVE record — CVE-2026-96940
- Microsoft — KB5129958, security update for Exchange Server 2016 CU23, 2 Oct 2026
- Help Net Security — Out-of-band Exchange Server update fixes high-severity mailbox access bug, 5 Oct 2026
- CloudSEK — MALFEX: a malicious npm postinstall, 30 Sep 2026
- SecurityWeek — Long-running npm malware campaign accumulates 40,000 downloads, 6 Oct 2026
- Hackread — MALFEX npm attack spreads Windows RAT, steals Discord and browser data
- CISA — Known Exploited Vulnerabilities catalog, catalog version 2026.10.04
- CISA — Known Exploited Vulnerabilities catalog data
Provenance: compiled 6 October 2026 by Threat Vector Management from a sweep of vendor, government and researcher sources, with research and fact-checking support from Claude (Anthropic). Every CVE identifier, version string, score, date and indicator was checked against its cited primary record or researcher publication on the day of publication; the hunt logic is our analysis of those records.