Threat Summary
Live AlienVault OTX telemetry confirms that Kimsuky — the North Korea-nexus APT group tracked under aliases including Thallium, Velvet Chollima, and APT43 — has materially evolved its long-running Operation GitPower campaign. Between August 11–19, 2026, researchers collected thirteen distinct LNK variants disguised as financial statements, business contracts, and corporate documents, all employing a novel C2 channel: GitHub Personal Access Tokens (PATs) used to authenticate against legitimate GitHub repositories acting as dead-drop resolvers and command channels.
The most significant evolution is Kimsuky's adoption of an AI agent ('opencode') to mass-generate convincing decoy documents. This represents an operational inflection point: the actor can now produce localized, contextually appropriate lures at scale — finance-themed lures for banks, policy documents for government ministries — without human authoring bottlenecks. Combined with obfuscated PowerShell loaders delivered through custom decoders and dedicated anti-analysis routines, this campaign demonstrates a deliberate investment in evading both signature-based and behavioral detection.
Targeting: Finance and Government sectors (consistent with Kimsuky's historic mandate of espionage against South Korean, Japanese, and Western foreign-policy and financial entities).
Objective: Long-dwell cyber espionage — initial access via weaponized LNK, staged PowerShell payload delivery, and resilient C2 riding on trusted GitHub infrastructure to blend with legitimate developer traffic.
Threat Actor / Malware Profile
Adversary: Kimsuky (APT43 / Thallium)
Kimsuky is a DPRK state-sponsored group active since at least 2012, primarily tasked with intelligence collection supporting North Korean strategic interests. The group is known for spearphishing excellence, extensive use of script-based loaders (PowerShell, VBScript, HTA), and abuse of legitimate cloud services (Google Drive, OneDrive, GitHub) for C2 and staging.
Attack Chain — Operation GitPower (2026 Evolution)
| Stage | Behavior |
|---|---|
| Delivery | Spearphishing emails carrying ZIP/compressed attachments containing weaponized .lnk files themed as financial and business documents |
| Decoy Generation | AI agent 'opencode' used to programmatically generate convincing decoy documents, improving lure credibility and campaign throughput |
| Execution | LNK shortcut invokes powershell.exe (typically with -enc, -w hidden, or abbreviated flags) to execute embedded or staged commands |
| Decoding | Obfuscated PowerShell loaders deobfuscated at runtime via custom decoder routines (character substitution, base64 layering, string concatenation) |
| C2 | GitHub Personal Access Tokens (PATs) authenticate against attacker-controlled GitHub repositories; issue comments, gist content, or raw file blobs serve as command channels and payload staging |
| Anti-Analysis | New routines observed in August 2026 samples: sandbox/debugger checks, analysis-environment detection, delayed execution, and conditional payload decryption |
Why GitHub PAT C2 Matters
Using PATs over api.github.com provides three operational advantages to the actor:
- Reputation laundering — GitHub is whitelisted in nearly every enterprise egress policy, especially in finance and government organizations with developer populations.
- Encrypted, authenticated channel — all C2 rides TLS to a trusted domain; token-based auth prevents casual inspection of the malicious repositories.
- Rapid infrastructure rotation — PATs and repos can be burned and replaced in minutes with zero hosting cost.
Detection implication: network-layer blocking of github.com is not viable. Detection must pivot to behavioral signals — Office/LNK child processes spawning PowerShell, PowerShell reaching GitHub API endpoints, and token-authenticated API patterns.
IOC Analysis
The OTX pulse publishes 17 indicators, dominated by file hashes:
- 1× SHA-256 (
f1bd58...fe91091) — likely a primary LNK sample or loader; the highest-fidelity pivot for retro-hunting in EDR telemetry and malware sandboxes. - 6× MD5 hashes — variant LNK files and loader components from the August 11–19 collection window. MD5s are brittle (single-byte changes break them) but excellent for confirming known-bad samples in email gateways, download caches, and quarantine stores.
Notably absent: network IOCs (IPs/domains). This is consistent with the campaign's C2 design — traffic goes to api.github.com / raw.githubusercontent.com, so traditional network blocklisting yields nothing. SOC teams must instead:
- Ingest hashes into EDR blocklists and retro-hunt across email attachment stores, browser download directories, and
%TEMP%/%APPDATA%write events. - Hunt behaviorally for the GitHub-PAT C2 pattern: non-browser processes (
powershell.exe,cmd.exe,wscript.exe) establishing TLS sessions toapi.github.comorraw.githubusercontent.com. - Detonate the hashes in a sandbox (ANY.RUN, Hybrid Analysis, Joe Sandbox) to extract the GitHub account/repo names and PAT strings, which become far more durable pivots than the file hashes themselves.
- Coordinate with GitHub Trust & Safety to suspend identified PATs and repositories, severing C2.
Detection Engineering
---
title: Kimsuky Operation GitPower - Malicious LNK Spawning PowerShell Loader
id: 9c2a1f44-7b3e-4d51-9a01-6f2b8c4d5e10
status: experimental
description: Detects LNK-driven execution chains consistent with Kimsuky Operation GitPower where a shortcut file launches hidden or encoded PowerShell loaders
author: Security Arsenal Threat Intelligence
references:
- https://www.genians.co.kr/blog/threat_intelligence/ai-agent-opencode
- https://otx.alienvault.com/pulse/
date: 2026/09/08
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\explorer.exe'
- '\cmd.exe'
- '\msedge.exe'
- '\chrome.exe'
- '\OUTLOOK.EXE'
selection_image:
Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
selection_flags:
CommandLine|contains:
- ' -enc '
- ' -e '
- ' -w hidden'
- ' -WindowStyle Hidden'
- 'FromBase64String'
- 'IEX'
- 'DownloadString'
condition: selection_parent and selection_image and 1 of selection_flags
falsepositives:
- Administrative scripts launched manually via shortcuts
level: high
tags:
- attack.execution
- attack.t1059.001
- attack.t1204.002
---
title: Kimsuky Operation GitPower - Non-Browser Process Contacting GitHub API (PAT-Based C2)
id: 3e7b9d12-5c4a-4f68-8b22-1a9c0d6e7f31
status: experimental
description: Detects script interpreters and LOLBins establishing connections to GitHub API/raw endpoints, consistent with Kimsuky's GitHub PAT-based C2 channel
author: Security Arsenal Threat Intelligence
references:
- https://www.genians.co.kr/blog/threat_intelligence/ai-agent-opencode
date: 2026/09/08
logsource:
category: network_connection
product: windows
detection:
selection_process:
Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
- '\cmd.exe'
- '\wscript.exe'
- '\cscript.exe'
- '\mshta.exe'
- '\rundll32.exe'
- '\curl.exe'
- '\wget.exe'
selection_domain:
DestinationHostname|contains:
- 'api.github.com'
- 'raw.githubusercontent.com'
- 'gist.github.com'
- 'objects.githubusercontent.com'
condition: selection_process and selection_domain
falsepositives:
- Developer tooling, package managers, and CI agents on engineering workstations - baseline per host role
level: high
tags:
- attack.command_and_control
- attack.t1102
- attack.t1071.001
---
title: Kimsuky Operation GitPower - Encoded or Obfuscated PowerShell with Custom Decoder Patterns
id: 7f1d5a83-2e9b-4c74-b133-8d4e6f0a2c59
status: experimental
description: Detects obfuscated PowerShell command lines containing string-manipulation and decoding routines matching Kimsuky custom decoder behavior, including anti-analysis sleep/delay patterns
author: Security Arsenal Threat Intelligence
references:
- https://www.genians.co.kr/blog/threat_intelligence/ai-agent-opencode
date: 2026/09/08
logsource:
category: process_creation
product: windows
detection:
selection_image:
Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
selection_obfuscation:
CommandLine|contains:
- '-replace'
- '[char]'
- 'Join-String'
- '-join'
- 'Reverse'
- 'Start-Sleep'
- 'FromBase64String'
- '.Substring('
- 'GetEnumerator'
condition: selection_image and 2 of selection_obfuscation
falsepositives:
- Legitimate administrative one-liners with string manipulation; tune per environment
level: medium
tags:
- attack.defense_evasion
- attack.t1027
- attack.t1059.001
// Kimsuky Operation GitPower Hunt: LNK-launched PowerShell + GitHub PAT C2
// Microsoft Sentinel / Microsoft 365 Defender
let ioc_hashes = dynamic([
"f1bd5817678f498966f033f61b617dee5c8e81191901fea7c4a89146bfe91091",
"10780939962b54addc9d31f57d80edfc",
"1523a2fcc901965ab4568d9fe829e4af",
"500e0bc0d7579fb338912770964076fe",
"685bfc6b2c29fbc16cfad908894add55",
"7a53089053b1381742856a5cf2b95f8b",
"8db2f20b719dcb7029d6296505622093",
"900e832c10d851bbdef3fb191a15db0e"
]);
let github_c2 = dynamic(["api.github.com", "raw.githubusercontent.com", "gist.github.com", "objects.githubusercontent.com"]);
// Part 1: Known-bad hash sightings in file events
let HashHits =
DeviceFileEvents
| where TimeGenerated > ago(14d)
| where SHA256 in~ (ioc_hashes) or MD5 in~ (ioc_hashes)
| project TimeGenerated, DeviceName, FileName, FolderPath, SHA256, MD5, InitiatingProcessFileName;
// Part 2: LNK-triggered PowerShell with obfuscation flags
let LnkChains =
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| where InitiatingProcessCommandLine has_any (".lnk")
or ProcessCommandLine has_any (" -enc ", "FromBase64String", " -w hidden", "WindowStyle Hidden", "IEX")
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName;
// Part 3: Non-browser processes talking to GitHub API (PAT C2 behavior)
let GithubC2 =
DeviceNetworkEvents
| where TimeGenerated > ago(14d)
| where RemoteUrl has_any (github_c2)
| where InitiatingProcessFileName in~ ("powershell.exe","pwsh.exe","cmd.exe","wscript.exe","cscript.exe","mshta.exe","rundll32.exe","curl.exe","wget.exe")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteUrl, RemoteIP, RemotePort;
HashHits
| union LnkChains, GithubC2
| sort by TimeGenerated desc
# Kimsuky Operation GitPower - Endpoint IOC & Behavior Hunt
# Run elevated across endpoints (or via EDR Live Response / GPO scheduled task)
# Checks: known-bad hashes, suspicious LNK files, encoded PowerShell artifacts, GitHub API connections
$ErrorActionPreference = 'SilentlyContinue'
$report = @()
$badMD5 = @(
'10780939962b54addc9d31f57d80edfc','1523a2fcc901965ab4568d9fe829e4af',
'500e0bc0d7579fb338912770964076fe','685bfc6b2c29fbc16cfad908894add55',
'7a53089053b1381742856a5cf2b95f8b','8db2f20b719dcb7029d6296505622093',
'900e832c10d851bbdef3fb191a15db0e'
)
$badSHA256 = @('f1bd5817678f498966f033f61b617dee5c8e81191901fea7c4a89146bfe91091')
Write-Host "[1] Hash sweep of user-writable directories..."
$searchPaths = @("$env:TEMP","$env:APPDATA","$env:LOCALAPPDATA","$env:USERPROFILE\Downloads","$env:USERPROFILE\Desktop","C:\ProgramData")
foreach ($p in $searchPaths) {
Get-ChildItem -Path $p -Recurse -File -Include *.lnk,*.ps1,*.zip -ErrorAction SilentlyContinue | ForEach-Object {
$m = (Get-FileHash $_.FullName -Algorithm MD5).Hash.ToLower()
$s = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower()
if ($badMD5 -contains $m -or $badSHA256 -contains $s) {
$report += [PSCustomObject]@{Check='HashMatch'; Path=$_.FullName; MD5=$m; SHA256=$s; Detail='KNOWN KIMSUKY IOC'}
}
}
}
Write-Host "[2] Scanning .lnk files for PowerShell targets..."
$wsh = New-Object -ComObject WScript.Shell
foreach ($p in $searchPaths) {
Get-ChildItem -Path $p -Recurse -Filter *.lnk -ErrorAction SilentlyContinue | ForEach-Object {
$sc = $wsh.CreateShortcut($_.FullName)
if ($sc.TargetPath -match 'powershell|pwsh|mshta|wscript' -or $sc.Arguments -match '-enc|FromBase64String|IEX|hidden') {
$report += [PSCustomObject]@{Check='SuspiciousLNK'; Path=$_.FullName; MD5=''; SHA256=''; Detail="Target=$($sc.TargetPath) Args=$($sc.Arguments)"}
}
}
}
Write-Host "[3] Checking active connections to GitHub API endpoints..."
$conns = Get-NetTCPConnection -State Established | Where-Object { $_.RemotePort -eq 443 }
foreach ($c in $conns) {
$proc = Get-Process -Id $c.OwningProcess -ErrorAction SilentlyContinue
if ($proc.ProcessName -match 'powershell|pwsh|cmd|wscript|cscript|mshta|rundll32|curl|wget') {
try {
$dns = (Resolve-DnsName $c.RemoteAddress -ErrorAction Stop).NameHost
} catch { $dns = '' }
if ($dns -match 'github|githubusercontent' -or $c.RemoteAddress -match '^140\.82\.|^185\.199\.') {
$report += [PSCustomObject]@{Check='GithubC2'; Path=$proc.Path; MD5=''; SHA256=''; Detail="$($proc.ProcessName) -> $($c.RemoteAddress):443 ($dns)"}
}
}
}
Write-Host "[4] Checking PowerShell history for obfuscation artifacts..."
Get-ChildItem "$env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine" -Filter *.txt -Recurse | ForEach-Object {
$hits = Select-String -Path $_.FullName -Pattern '-enc |FromBase64String|Start-Sleep|-replace|\[char\]' -AllMatches
if ($hits) { $report += [PSCustomObject]@{Check='PSHistory'; Path=$_.FullName; MD5=''; SHA256=''; Detail="$(($hits | Measure-Object).Count) suspicious lines"} }
}
Write-Host "`n===== KIMSUKY GITPOWER HUNT RESULTS ====="
if ($report.Count -eq 0) { Write-Host "No indicators found on $env:COMPUTERNAME" }
else { $report | Format-Table -AutoSize; $report | Export-Csv ".\kimsuky_hunt_$env:COMPUTERNAME.csv" -NoTypeInformation }
Response Priorities
Immediate (0–4 hours)
- Ingest all 17 IOC hashes into EDR blocklists, email gateway attachment filtering, and web proxy download inspection. Retro-hunt 30 days of file-creation telemetry for the SHA-256 and MD5 values.
- Deploy the Sigma rules above to your SIEM; prioritize alerting on script interpreters connecting to
api.github.com/raw.githubusercontent.com. - Block .lnk attachments at the email perimeter for Finance and Government business units; quarantine ZIP archives containing shortcut files.
- Sweep user Download/Desktop/Temp directories using the PowerShell hunt script on any host that received finance-themed email attachments in the August–September 2026 window.
24 Hours
- Credential exposure assessment: Kimsuky operations routinely pair initial access with credential harvesting and session-token theft. Force password resets and revoke active sessions for any user whose host tripped a hunt rule; prioritize privileged and finance-operations accounts.
- Audit GitHub API egress: review proxy/ZTNA logs for PAT-authenticated requests (Authorization headers against
api.github.com) from non-developer endpoints; extract repo/account names and submit takedown requests to GitHub Trust & Safety. - Detonate collected samples in an isolated sandbox to recover C2 repository names, PAT strings, and second-stage payloads; feed new indicators back into detection.
- Review mailbox rules and OAuth grants on potentially compromised accounts — Kimsuky has historically abused inbox forwarding rules for persistent collection.
1 Week
- Enforce LNK execution policy: use WDAC/AppLocker to block PowerShell child processes spawned from Explorer via
.lnkexecution, and enable PowerShell Script Block Logging + AMSI fleet-wide if not already present. - GitHub egress segmentation: route developer GitHub API traffic through an authenticated proxy and alert on GitHub API access from non-developer VLANs/device classes.
- Decoy-resilience awareness training for Finance and Government staff — specifically addressing AI-generated, contextually accurate lure documents, which defeat legacy "spot the typo" heuristics.
- Tabletop the PAT-C2 scenario: validate that IR runbooks cover legitimate-service C2 takedowns (GitHub/Drive/Gist) and that legal/comms paths for third-party abuse reports are pre-approved.
Related Resources
Security Arsenal Incident Response Managed SOC & MDR Services AlertMonitor Threat Detection From The Dark Side Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.