Review of a LinkedIn scam vacancy

Review of a LinkedIn scam vacancy

Tags
deep dive
javascript
reverse engineering
Published
Jun 4, 2025
Recently, a former colleague sent me a repository that’s attached to those scam job postings where they ask you to follow a link, install a project, and run it. I never saw the text of the job posting itself, but that wasn’t the interesting part. As an engineer, I wanted to know when exactly the malicious action takes place, how well it’s hidden, and what it actually does.
The project itself looks like a typical React + Express monorepo with a basic interface and functionality – the kind of thing modern AI tools can easily scaffold. A few red flags immediately stood out:
  • Hosted on Bitbucket, not GitHub or GitLab
  • Commit author not linked to a real Bitbucket account
  • Installation guide suggests using the -force flag with npm i
  • Only one commit, with the telling name “POC”
Browsing the file structure, I got the impression the project was clearly stolen from somewhere else and could even pass as a potential product. The code looked like sloppy “vibe coding over beer.” So if the idea was to hand this to someone for an “assessment,” there’s enough to talk about.
(P.S. After writing the post, I found a tweet announcing this project’s release on February 26, 2024, with ~50k views. So yes, it was stolen.)

Looking for the Entry Point

The real question was where the malicious part hides. If the whole point is to get the victim to install and run the project, then the worst must happen either during setup or at startup (especially given the --force hint).
That led me to package.json, expecting a postinstall script. But that would be too obvious – and indeed, all scripts matched the default CRA setup. Of course, malicious scripts can also be hidden inside dependencies.
I scanned through the dependency list. Since the project was Web3-related (outside my daily focus), most of the packages were unfamiliar – and therefore suspicious. I started checking each one on npm (and GitHub if linked).
When I got to nexpi-session, I felt something was off.
  • The name suggested session handling (a sensitive area by default)
  • “nexpi”? Never heard of it
  • Uploaded to npm only 9 days ago
  • 37 downloads total → 37 potential victims
  • Linked GitHub repo returned a 404
  • Author: no-name, no avatar
Bingo?

Inside the Package

On npm, you can browse a package’s content directly, so I did. The package turned out to be a modified version of express-session (originally by Sencha Inc. and TJ Holowaychuk – pretty big names). Copyrights were left intact, probably to look legit, or just because attackers assumed nobody reads dependency code.
The package had 4 files: four session storage strategies. I opened cookie.js first, since the backend code hinted that authentication relied on cookies.
And there it was. Line 52: a suspicious function doing only two things – axios.get() and eval on the response. Even worse, it was called unconditionally at the end of the file, meaning it would execute as soon as the server served any page.
notion image

The Payload

So the injection point was found. But what happens inside that eval?
I reconstructed the target URL from variables. Not wanting to risk opening it in my browser, I used an online wget. The response was a heavily obfuscated self-invoking function. After deobfuscation (thanks to some colleagues in AI), here’s what it did:
  • Monkey-patched console logging functions to suppress errors
  • Scanned directories for Chrome, Brave, Opera, Firefox, and popular extensions
  • Looked for browser profiles, wallet files, keychains, and local databases
  • Collected everything into a folder and exfiltrated it to the attacker’s server
At this point, I could’ve stopped. The script was clearly malicious. But while drafting this post, I got curious and dug deeper – into another line that downloaded yet another payload. That’s where it got even nastier.
notion image

The Python Chain

This payload was a Python script. Not my usual frontend territory, but I dived in.
It checked if Python was installed on the victim’s machine; if not, it downloaded two different versions to increase the odds of success. Then it fetched another obfuscated Python script, compressed with zlib + base64, plus a reversed base64 string – repeated 64 times.
At first I thought it was a joke, since each decode still gave me another encoded version. After manually attempting 3 rounds, I realized it wasn’t feasible and wrote a self-decoder script (with the help of Perplexity). Finally, I got the real payload.
So what does it do?
notion image
  • Downloaded two more files, this time encoded 100 times
  • Launched them as separate processes
Once I analyzed them, it was clear: if execution reaches this stage, your machine is no longer yours. All your data is already in the darknet. The only “silver lining” is that it wasn’t ransomware by default – but it did establish a persistent two-way connection that could later be used to deliver ransomware.
Researchers attribute authorship to Lazarus Group. The most sophisticated script was built to survive autonomously for long periods, updating itself from 1000+ Pastebin links, and encrypted with the !!HappyPenguin1950!!! public key… which refers to well-known events.

Reporting

I reported the npm package, and support removed it within 8 hours. Three hours later, the repo author force-pushed a new version, changing just one letter in the package name, but with the same payload. By then, installations had jumped to 59 (in only 3 hours, compared to 37 in the previous 9 days).
I reported again. The package was removed. As of writing, 5 days have passed with no new uploads. A small win 🏆
notion image

Epilogue

Here my journey into reverse engineering the sophisticated malware came to an end, and instead of a conclusion I’ll leave a comment from the header of one of the scripts:
Loading code example...
After finishing my own analysis, I looked up other references to this malware. I found:
And yes, the deobfuscated code is already published on GitHub back in February – for educational purposes ofcourse.