GopherWhisper: China-Aligned APT Uses Slack, Discord, and Microsoft 365 Outlook as Command-and-Control

Introduction

ESET researchers have publicly named a new China-aligned APT group — GopherWhisper — and published a detailed analysis of its toolset and operations against Mongolian government targets. The group's signature is its almost-exclusive reliance on legitimate cloud collaboration services for command-and-control: Slack, Discord, Microsoft 365 Outlook (via the Graph API), and the file.io anonymous file-share. Twelve government systems at one Mongolian institution were confirmed backdoored, with evidence of dozens more victims, and the campaign has been running quietly since at least November 2023. ESET extracted thousands of C&C messages from misconfigured Slack and Discord channels because the operators didn't clear their logs — a rare deep look at how this kind of "living-off-trusted-services" tradecraft actually plays out.

What Happened

ESET's investigation began in January 2025 when analysts found a previously undocumented backdoor (later named LaxGopher) on a Mongolian government endpoint. Pulling on that thread surfaced an entire malware family, all written predominantly in Go (hence "Gopher" — the Go mascot). The toolset:

Component Language Role C2 Channel
LaxGopher Go Primary backdoor; runs cmd.exe commands, returns output Private Slack server (Slack API tokens)
RatGopher Go Secondary backdoor; same shell capabilities Private Discord server (Discord API tokens)
BoxOfFriends Go Backdoor using Microsoft 365 Outlook draft email messages for both inbound commands and outbound data M365 Outlook via Microsoft Graph API
JabGopher Go Process injector
CompactGopher Go Exfiltration tool to file.io file.io anonymous file share
FriendDelivery C++ DLL Loader; side-loads via the filename whisper.dll and injects BoxOfFriends
SSLORDoor C++ Additional backdoor used selectively

The signature C2 trick is using draft messages inside Outlook mailboxes as a dead-drop. BoxOfFriends authenticates to Microsoft Graph as a compromised mailbox, reads commands the operator left as draft emails, executes them, and writes the output back as another draft. No mail is ever sent. From a network-monitoring perspective the host just looks like it's syncing email through graph.microsoft.com — the same TLS endpoint that every legitimate Outlook client on every Windows machine talks to.

ESET extracted Slack and Discord API tokens from analyzed samples and pulled thousands of message-history records from the operator-controlled channels. The operators had used some of those servers initially as test environments for the malware, then never created clean ones — so ESET got a first-hand view of their build, debug, and post-compromise activity logs.

ESET attributes GopherWhisper to a China-aligned actor with targeting overlapping Worok, Vicious Panda, and Mustang Panda — the same regional cluster historically focused on Mongolia, Central Asia, and minority-religion / opposition targets. SecurityWeek, The Hacker News, and Dark Reading all picked up the ESET analysis on April 23–25, 2026.

Why It Matters

Living-off-trusted-sites (LOTS) C2 isn't new — Cobalt Strike's profile templates have included Slack/Telegram emulation for years. What's new is how thoroughly GopherWhisper has industrialized the pattern. Every component talks to a different legitimate service. Network defenses built around URL/IP reputation, DNS sinkholing, and TLS cert anomalies see nothing — because everything is going to slack.com, discord.com, and graph.microsoft.com. Egress filtering rules that block "C2 infrastructure" but allowlist productivity apps are exactly inverted from where the threat is.

The Outlook-drafts-as-C2 pattern is particularly nasty because Microsoft 365 audit logs do not by default capture draft create/modify operations at the granularity needed to detect the technique. Defenders who think they have full Graph API logging often find out during an investigation that they were missing the relevant MailItemsAccessed / MessageDraft events.

For DevOps / security teams the operational lesson is: trust boundaries inside SaaS matter as much as network egress filtering. A compromised endpoint with valid M365 credentials can use Outlook itself as a C2 channel. Conditional-access policies, app-permission audits, and Graph API monitoring become the actual control points.

Who Is Affected

  • Government, defense, and policy-research targets in Mongolia (confirmed) and likely other Central Asian / Russia-adjacent / opposition political targets
  • Any organization where compromised endpoints have valid M365 credentials with Outlook mailbox access — and where Slack/Discord usage is allowed without app-permission controls
  • Companies that whitelist *.slack.com, *.discord.com, graph.microsoft.com, and file.io in egress without flow-level monitoring
  • The pattern is replicable; expect copycat actors. China-aligned crews historically share tradecraft within ~6 months

How to Protect Yourself

Step 1: Identify whether GopherWhisper-style tradecraft would slip past your current controls.

# Inventory which hosts can reach the abused services
# (Run from your egress monitoring or NetFlow store)
# Hosts contacting Slack, Discord, Outlook Graph, and file.io
zcat /var/log/netflow/*.gz | jq -r 'select(.dest_domain | test("slack\\.com|discord\\.com|graph\\.microsoft\\.com|file\\.io")) | .src_ip' | sort -u

For SOCs with Splunk:

index=netflow OR index=zeek dest_domain IN ("*.slack.com","*.discord.com","graph.microsoft.com","file.io")
| stats count by src_host, dest_domain
| where count > 100

Hosts that should not be talking to Slack/Discord (servers, build agents, headless workstations) are the highest-value hunt targets.

Step 2: Hunt for the GopherWhisper-specific IOCs ESET published.

# Check for the side-loaded loader DLL
find / -type f -name "whisper.dll" 2>/dev/null

# YARA hunt for Go-binary backdoor patterns published by ESET
# (Replace with the ESET-published rule once available; baseline rules below)
yara -r gopherwhisper.yar /

A starter YARA pattern (combine with ESET's published rules):

rule GopherWhisper_LaxGopher_Strings {
    meta:
        author = "you"
        description = "Strings observed in GopherWhisper LaxGopher backdoor"
    strings:
        $a = "slack.com/api/" ascii
        $b = "xoxb-" ascii   // Slack bot token prefix
        $c = "xoxp-" ascii   // Slack user token prefix
        $d = "/conversations.history" ascii
        $e = "/files.upload" ascii
    condition:
        all of them
}

Step 3: Lock down Microsoft Graph API access. The BoxOfFriends Outlook-drafts technique requires Mail.ReadWrite (or similar) Graph scope on a compromised account. Two controls neuter it:

# Audit which apps in your tenant have Mail.ReadWrite or Mail.Send-class scopes
Connect-MgGraph -Scopes "Application.Read.All","Directory.Read.All"
Get-MgServicePrincipal -All | ForEach-Object {
    $sp = $_
    $perms = Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $sp.Id -ErrorAction SilentlyContinue
    if ($perms) {
        $sp | Select-Object DisplayName, AppId, AppRoleAssignedTo
    }
} | Where-Object { $_.AppRoleAssignedTo -match "Mail\." }

# Restrict user consent to verified publishers only
Set-MgPolicyAuthorizationPolicy -DefaultUserRolePermissions @{AllowedToCreateApps=$false}
Update-MgPolicyAuthorizationPolicy -BodyParameter @{
    DefaultUserRolePermissions = @{
        PermissionGrantPoliciesAssigned = @("ManagePermissionGrantsForSelf.microsoft-user-default-low")
    }
}

Then enable Mailbox Audit Logging with MailItemsAccessed (default in M365) plus the broader MessageDraft events:

Set-Mailbox -Identity [email protected] -AuditEnabled $true `
    -AuditOwner @{Add="MailItemsAccessed","Update","SoftDelete","HardDelete"}

# Tenant-wide
Set-OrganizationConfig -AuditDisabled $false

Step 4: Monitor Slack and Discord at the workspace/server level for unusual API token use. Slack publishes audit events through its Audit Logs API; pipe them to your SIEM:

curl -s -H "Authorization: Bearer $SLACK_AUDIT_TOKEN" \
    "https://api.slack.com/audit/v1/logs?action=user_login&limit=200"; \
    | jq '.entries[] | select(.entity.user.is_bot == true)'

Look for bot tokens you don't recognize, especially with chat:write, files:write, or conversations:history scopes.

For corporate Discord, restrict bot creation and audit installed apps:

Server Settings → Integrations → review every Bot and App
- Disable any with "Manage Server", "Read Message History" you don't recognize
- Enable Server Insights / Audit Log monitoring

Step 5: Egress filtering refinement. Don't try to block Slack/Discord/Graph (you can't, your users need them). Instead:

  • Block from server / workstation roles that should never talk to them — domain controllers, build agents, jump hosts, OT workstations
  • Use a SASE gateway that does TLS inspection and can flag unusual API call patterns (LaxGopher's polling is recognizably bot-like compared to a human's Slack activity)
  • Block file.io outright at the corporate proxy unless there's a documented business need:
# In your egress proxy / squid / SASE
acl bad_filesharing dstdomain .file.io .anonfiles.com .gofile.io .pixeldrain.com
http_access deny bad_filesharing

Step 6: Treat M365 / Slack / Discord credentials as identity infrastructure. They are. ShinyHunters' vishing playbook (see today's ADT story) and GopherWhisper's LOTS C2 both exploit the fact that compromised SaaS credentials are the new perimeter. Phishing-resistant MFA on Microsoft Entra and Slack SSO (with FIDO2 keys), conditional-access requiring managed devices, and aggressive session-revocation hygiene are the controls that matter.

Source