Back to Intelligence

PamStealer macOS Stealer Evolves: Live C2-Side Decryption and Multi-Layer Persistence — Detection and Response Guide

SA
Security Arsenal Team
September 25, 2026
12 min read

Jamf Threat Labs has published new research on an evolved version of PamStealer, a macOS information stealer that has materially raised the bar against defenders and malware analysts alike. The latest artifacts retain the same JavaScript for Automation (JXA) dropper delivery mechanism seen in earlier variants, but introduce two capabilities that directly target our detection and analysis workflows:

  1. Server-side decryption chain — the main malicious payload can only be recovered using key material fetched live from the attacker's command-and-control (C2) infrastructure. Earlier variants embedded key material in the samples themselves, meaning analysts could statically decrypt and triage the payload offline. That option is now gone.
  2. Multi-layer persistence — the malware no longer relies on a single foothold, stacking redundant persistence mechanisms so that removing one artifact does not remove the infection.

This matters to every organization with macOS endpoints in the fleet — which in 2026 is effectively every enterprise. Infostealers like PamStealer are the primary initial-access vector for downstream ransomware and business email compromise: they harvest browser credentials, session cookies, keychain material, cryptocurrency wallets, and developer secrets, which are then sold or weaponized within days. The architectural shift to server-side decryption is not a curiosity — it is an anti-analysis control that defeats sandbox detonation, static signature creation, and post-mortem forensic recovery of the payload. If your detection strategy relies on capturing and reversing the final binary, you are now blind. Detection must move up the kill chain to the dropper, the network, and the persistence layers.

Technical Analysis

Affected Platforms

  • Platform: Apple macOS (all currently supported versions; the JXA/osascript execution path is architecture-agnostic across Intel and Apple Silicon)
  • Delivery vector: Social-engineered lure with an updated delivery method (per Jamf, the lure and delivery changed from earlier variants while the JXA dropper core stayed the same)
  • Execution chain: JXA script interpreted by the native osascript binary — a signed, Apple-shipped tool, which means application allowlisting based on code signing alone will not stop it
  • Attribution/Research: Jamf Threat Labs

No CVE is associated with this campaign — PamStealer abuses legitimate macOS functionality (JXA automation, launch services, user-level persistence) rather than exploiting a software vulnerability. That is precisely what makes it dangerous: there is nothing to patch. Defense is entirely behavioral.

Why Server-Side Decryption Is a Defensive Problem

The most consequential change is architectural. In previous PamStealer variants, the decryption key material was embedded in the sample. A malware analyst (or an automated sandbox) could recover the key, decrypt the payload, and produce static detections, YARA rules, and IOCs for the final stealer binary.

In the new variant:

  • The JXA dropper reaches out to live C2 infrastructure to retrieve the decryption chain.
  • The payload exists in plaintext only in memory, only on an infected host, and only while the C2 is operational.
  • If the C2 is sinkholed, taken down, or geo-fenced away from your sandbox, the payload is unrecoverable. Samples captured from the wire or disk are cryptographically inert.
  • This also enables the operator to selectively deploy — the C2 can refuse to serve keys to known sandbox IP ranges, VPN egress points, or non-target geographies.

Defensive implication: you cannot wait for payload signatures. Your detection surface is (a) the JXA dropper behavior, (b) the C2 key-retrieval network transaction, and (c) the persistence artifacts. All three are observable with standard telemetry.

Attack Chain (Defender's View)

  1. Lure & delivery — victim is socially engineered into executing the dropper (updated lure per Jamf; typically a trojanized application, fake update, or malicious document prompting the user to run a script).
  2. JXA execution — the dropper runs under /usr/bin/osascript with JavaScript syntax (-l JavaScript), often using the Objective-C bridge (ObjC.import) and doShellScript to drop payloads and run shell commands.
  3. C2 key retrieval — the dropper (or a dropped first-stage) contacts the C2 to fetch decryption key material. This may be direct HTTPS from the script process or proxied through curl.
  4. In-memory payload recovery — the stealer payload is decrypted and executed, harvesting credentials, cookies, keychain items, and wallets.
  5. Multi-layer persistence — multiple persistence mechanisms are installed so partial remediation fails. Expect combinations of: user LaunchAgents (~/Library/LaunchAgents/*.plist), LaunchDaemons where privileges allow, and re-infection logic in the staged components. Each layer should be treated as an independent detection opportunity.
  6. Exfiltration — harvested data is staged, archived, and sent to C2 infrastructure over HTTPS.

Exploitation Status

This is an active, in-the-wild malware campaign flagged by Jamf Threat Labs in current telemetry — not a theoretical technique. The updated lures and delivery methods indicate an operator actively iterating to improve infection rates. Treat any JXA-driven execution chain on macOS endpoints as hostile until proven otherwise.

Detection & Response

The detection philosophy here: you will not reliably catch the decrypted payload, so catch everything around it. The highest-fidelity signals are (1) osascript executing JavaScript with shell bridging, (2) script interpreters making unexpected network connections (key retrieval), and (3) LaunchAgent/Daemon plist creation by non-installer processes.

Sigma Rules

YAML
---
title: macOS JXA Execution via Osascript with Shell Bridging
tid: 3f8a2c11-9b4e-4d21-a7c3-5e1f6a8b9c2d
status: experimental
description: Detects execution of JavaScript for Automation (JXA) through osascript using the -l JavaScript flag or Objective-C bridge/doShellScript patterns associated with PamStealer and other macOS stealers. JXA droppers abuse the signed osascript binary to bypass naive allowlisting.
references:
  - https://thehackernews.com/2026/09/pamstealer-macos-malware-adds-live-c2.html
  - https://attack.mitre.org/techniques/T1059/002/
author: Security Arsenal
date: 2026/09/25
tags:
  - attack.execution
  - attack.t1059.002
logsource:
  category: process_creation
  product: macos
detection:
  selection_img:
    Image|endswith: '/osascript'
  selection_js:
    CommandLine|contains:
      - '-l JavaScript'
      - 'ObjC.import'
      - 'doShellScript'
      - '$.NS'
  condition: selection_img and selection_js
falsepositives:
  - Legitimate macOS automation workflows (rare in enterprise environments; baseline developer and IT admin machines)
  - MDM-delivered automation scripts - verify with your MDM administrator
level: high
---
title: macOS LaunchAgent or LaunchDaemon Persistence Created by Script Interpreter
tid: 7c1d4e92-6a3b-4f58-b2e9-8d4c1a5f7e3b
status: experimental
description: Detects creation of LaunchAgent or LaunchDaemon plist files by script interpreters or non-installer processes, consistent with PamStealer's multi-layer persistence. Legitimate persistence is normally installed by signed package installers, not by osascript, curl, or scripts executing from temporary directories.
references:
  - https://thehackernews.com/2026/09/pamstealer-macos-malware-adds-live-c2.html
  - https://attack.mitre.org/techniques/T1543/001/
  - https://attack.mitre.org/techniques/T1543/004/
author: Security Arsenal
date: 2026/09/25
tags:
  - attack.persistence
  - attack.t1543.001
  - attack.t1543.004
logsource:
  category: file_event
  product: macos
detection:
  selection_path:
    TargetFilename|contains:
      - '/Library/LaunchAgents/'
      - '/Library/LaunchDaemons/'
  selection_ext:
    TargetFilename|endswith: '.plist'
  filter_installers:
    Image|endswith:
      - '/installer'
      - '/packagekitd'
      - '/softwareupdated'
      - '/installd'
  condition: selection_path and selection_ext and not filter_installers
falsepositives:
  - Enterprise software deployment tools writing launch plists - allowlist your MDM agent binary paths
level: high
---
title: Script Interpreter Spawning Network Utility for C2 Retrieval on macOS
tid: 2e9b5f48-1c7d-4a63-9e5b-3f8a2c6d1e94
status: experimental
description: Detects osascript or shell interpreters spawning curl/wget to fetch remote content, consistent with PamStealer retrieving server-side decryption key material from live C2. The payload cannot be decrypted without this transaction, making it a high-value choke point.
references:
  - https://thehackernews.com/2026/09/pamstealer-macos-malware-adds-live-c2.html
  - https://attack.mitre.org/techniques/T1105/
  - https://attack.mitre.org/techniques/T1071/001/
author: Security Arsenal
date: 2026/09/25
tags:
  - attack.command_and_control
  - attack.t1105
  - attack.t1071.001
logsource:
  category: process_creation
  product: macos
detection:
  selection_parent:
    ParentImage|endswith:
      - '/osascript'
      - '/bash'
      - '/zsh'
      - '/python'
      - '/python3'
  selection_child:
    Image|endswith:
      - '/curl'
      - '/wget'
  selection_tmp_parent:
    ParentCommandLine|contains:
      - '/tmp/'
      - '/private/tmp/'
      - '/var/folders/'
      - '/Users/Shared/'
  condition: selection_child and (selection_parent or selection_tmp_parent)
falsepositives:
  - Developer tooling and bootstrap scripts - scope by parent process path and destination domain reputation
level: high

Microsoft Sentinel / Defender KQL

This query assumes macOS endpoints are onboarded to Microsoft Defender for Endpoint (which supports macOS) or that macOS process/network telemetry reaches Sentinel via Syslog/CEF. It hunts the three observable stages: JXA execution, persistence writes, and C2 retrieval behavior.

KQL — Microsoft Sentinel / Defender
// PamStealer macOS hunt: JXA dropper, LaunchAgent persistence, and C2 fetch behavior
// Stage 1: JXA execution via osascript
let JXAExec = DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where ProcessCommandLine has_any ("-l JavaScript", "ObjC.import", "doShellScript")
   and (FileName =~ "osascript" or ProcessCommandLine has "/usr/bin/osascript")
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, ProcessId, InitiatingProcessFileName;
// Stage 2: LaunchAgent/LaunchDaemon plist creation by non-installer processes
let PersistenceWrites = DeviceFileEvents
| where TimeGenerated > ago(14d)
| where FolderPath has_any ("/Library/LaunchAgents/", "/Library/LaunchDaemons/", "Library/LaunchAgents")
   and FolderPath endswith ".plist"
| where ActionType == "FileCreated"
| where InitiatingProcessFileName !in~ ("installer", "installd", "softwareupdated", "packagekitd")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FolderPath, FileName;
// Stage 3: Script interpreters spawning curl/wget (C2 key retrieval choke point)
let C2Fetch = DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where FileName in~ ("curl", "wget")
| where InitiatingProcessFileName in~ ("osascript", "bash", "zsh", "python", "python3")
   or InitiatingProcessCommandLine has_any ("/tmp/", "/Users/Shared/", "/var/folders/")
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine;
union JXAExec, PersistenceWrites, C2Fetch
| sort by TimeGenerated asc

Velociraptor VQL

For live-response on a suspected macOS host, this artifact pulls the persistence surface and the running script interpreters in one collection. Review every LaunchAgent that references an interpreter, a script path, or a binary in a user-writable/temporary location.

VQL — Velociraptor
-- PamStealer macOS triage: enumerate LaunchAgent/LaunchDaemon persistence and live osascript executions
SELECT FullPath AS PlistPath,
       read_file(filename=FullPath) AS PlistContent,
       timestamp(epoch=Mtime.Sec) AS ModifiedTime
FROM glob(globs=[
  '/Library/LaunchAgents/*.plist',
  '/Library/LaunchDaemons/*.plist',
  '/Users/*/Library/LaunchAgents/*.plist'
])
WHERE PlistContent =~ '(osascript|JavaScript|doShellScript|/tmp/|/Users/Shared/|curl|base64)'
VQL — Velociraptor
-- Live processes: osascript interpreters and script-spawned network utilities
SELECT Pid, Ppid, Name, CommandLine, Exe, Username, CreateTime
FROM pslist()
WHERE Name =~ '(?i)osascript|curl|wget'
   OR CommandLine =~ '(?i)-l JavaScript|ObjC.import|doShellScript'

Remediation / Triage Script (macOS Bash)

Run this on a suspected host (via your MDM or IR live-response channel) to enumerate persistence, flag PamStealer-consistent artifacts, and neutralize obvious footholds. It is deliberately conservative — it quarantines rather than deletes, and it does not touch Apple-signed system plists.

Bash / Shell
#!/bin/bash
# PamStealer macOS triage & containment - run as root via MDM/IR channel
QUAR="/var/root/pamstealer_quarantine_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$QUAR"

# 1. Snapshot running script interpreters and their network-spawning children
echo "=== Suspicious processes ===" | tee -a "$QUAR/report.txt"
ps aux | grep -Ei 'osascript|-l JavaScript|doShellScript' | grep -v grep | tee -a "$QUAR/report.txt"

# 2. Enumerate all persistence locations, flag interpreter/script-based plists
echo "=== LaunchAgent/Daemon review ===" | tee -a "$QUAR/report.txt"
for d in /Library/LaunchAgents /Library/LaunchDaemons /Users/*/Library/LaunchAgents; do
  for p in "$d"/*.plist; do
    [ -f "$p" ] || continue
    if grep -Eqi 'osascript|JavaScript|doShellScript|/tmp/|/Users/Shared/|curl|base64' "$p"; then
      echo "[SUSPECT] $p" | tee -a "$QUAR/report.txt"
      # Capture the label, unload, then quarantine (do not delete - preserve evidence)
      label=$(/usr/libexec/PlistBuddy -c "Print :Label" "$p" 2>/dev/null)
      [ -n "$label" ] && launchctl bootout gui/$(id -u $(stat -f%Su "$p")) "$p" 2>/dev/null
      launchctl unload "$p" 2>/dev/null
      cp "$p" "$QUAR/" && chmod 000 "$p"
      echo "[QUARANTINED] $p (label: $label)" | tee -a "$QUAR/report.txt"
    fi
  done
done

# 3. Kill live osascript instances running JavaScript (dropper/payload host)
pkill -f 'osascript.*-l JavaScript' 2>/dev/null

# 4. Capture outbound connections from script processes for C2 identification
echo "=== Network connections (script interpreters) ===" | tee -a "$QUAR/report.txt"
lsof -i -nP | grep -Ei 'osascript|curl|wget' | tee -a "$QUAR/report.txt"

# 5. Preserve evidence bundle for DFIR before any reboot
tar -czf "$QUAR.tar.gz" -C "$(dirname $QUAR)" "$(basename $QUAR)" 2>/dev/null
echo "Evidence bundle: $QUAR.tar.gz"

Remediation

There is no vendor patch for PamStealer — it abuses legitimate macOS capabilities. Remediation is architectural and procedural:

  1. Assume full compromise on any confirmed host. PamStealer is a credential stealer; eradication of the malware is only half the job. Rotate all credentials that were resident on the host: browser-stored passwords, session cookies (force re-authentication on all SSO/IdP sessions — cookie theft bypasses MFA), keychain entries, SSH keys, cloud CLI tokens (~/.aws, ~/.azure, ~/.config/gcloud), and developer secrets in repos or environment files.
  2. Remove ALL persistence layers simultaneously. The multi-layer design means cleaning one LaunchAgent while missing another results in re-infection on next boot. Enumerate all three persistence locations (/Library/LaunchAgents, /Library/LaunchDaemons, ~/Library/LaunchAgents) and cross-reference against known-good baselines before rebooting a cleaned host.
  3. Block the key-retrieval choke point. Because the payload is unrecoverable without a live C2 transaction, egress filtering is disproportionately effective here. Alert on — and where policy allows, block — outbound HTTPS from script interpreters (osascript, unsigned binaries in temp paths) to destinations with no business justification. Enforce DNS-based filtering with newly-registered-domain and low-reputation categories.
  4. Restrict JXA execution where feasible. Use your MDM or an endpoint security policy (e.g., Jamf Protect, MDE for Mac, Santa) to block or alert on osascript -l JavaScript execution for users who have no automation need. Very few enterprise roles legitimately run JXA. Apple has also continued tightening notarization and Gatekeeper enforcement — ensure Gatekeeper, XProtect, and System Integrity Protection are enabled and current on all endpoints.
  5. Baseline your LaunchAgents. Multi-layer persistence is only stealthy if you don't know what "normal" looks like. Maintain a gold-image inventory of launch plists per team/role and alert on deviations — this converts persistence installation into a high-fidelity, near-zero-noise detection.
  6. User education on the updated lure. Jamf notes the lure and delivery method changed. Brief users that macOS is an active target, that no legitimate software asks them to paste commands into Terminal, and that "verification" or "update" prompts requesting script execution should be reported to the SOC immediately.
  7. Preserve evidence before remediation. The server-side decryption design means that once the C2 is unreachable, the payload may be forensically unrecoverable. Capture memory and network state on live hosts before killing processes or isolating the machine, or you may lose the only window into the final-stage binary.

Reference: Jamf Threat Labs research via The Hacker News.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.