The npm package n8n-nodes-social-facebook v0.2.0, published under the account kerituni12, ships an 8 MB Go-compiled WebAssembly binary inside what presents as an n8n community node for Facebook automation. The binary targets Facebook Business Manager tokens, user access tokens, and Ads Manager credentials through the Graph API v23.0 and persists stolen sessions to the host filesystem. A built-in quota manager enforces plan-based rate limits and syncs with a remote server, consistent with a credential-harvesting service operated for multiple customers rather than a single attacker’s personal use.
The artifact
n8n-nodes-social-facebook v0.2.0 was first published on Sep 13, 2025 under the npm account kerituni12. The package.json repository field points to the botzvn GitHub organization. The n8n manifest declares two workflow nodes (Facebook.node.js, FacebookHttpRequest.node.js) and one credential provider (FacebookApi.credentials.js), all present under dist/nodes/Meta/ and dist/credentials/Meta/.
The files array also ships entries absent from any legitimate n8n node: dist/main.we (8,051,620 bytes), dist/we.js (145 KB), and a dist/utils/ directory with eight modules including init.js, common.js, debug-auth.js, rup.js, and wasm-utils.js. Roughly 63,000 _0x hex-index variable names span the thirteen shipped JavaScript files, all processed by gulp-javascript-obfuscator with RC4 string encryption. we.js is an obfuscated copy of Go’s standard wasm_exec.js runtime, a file normally shipped as readable source. Runtime dependencies include socks-proxy-agent and https-proxy-agent, neither required by n8n’s built-in HTTP client.
What it does
init.js runs at module load and injects Node.js built-in modules as named global variables: fs, os, path, and zlib. A fifth global provides node-fetch wrapped with HttpsProxyAgent and SocksProxyAgent, giving the binary outbound HTTP through configurable proxies. The Go WASM runtime has no native I/O imports. All 23 WASM imports are standard gojs bridge functions (syscall/js.valueCall, syscall/js.valueGet). These globals break the sandbox. The binary reaches the host filesystem, network, and OS through the JavaScript bridge.
we.js instantiates the Go WASM runtime and loads main.we from disk using the fs global that init.js placed. The .we extension is a renamed .wasm: the file begins with standard \x00asm magic bytes. Renaming it avoids scanner heuristics that match on the .wasm extension.
String extraction from main.we reveals the Go module path gowasm with subpackages core, config, handler, facebook, services, and httpclient, backed by 36 Go source files recovered from debug symbols. The binary harvests three classes of Facebook credential by scraping page HTML with regex: user access tokens matching EAAB via window\.__accessToken, page access tokens via Graph API exchange, and ads user access tokens matching EAAG from the Ads Manager onboarding page. Session parameters (fb_dtsg, jazoest, __hsi, __spin_t, compat_iframe_token) are scraped from live Facebook responses using dedicated extraction patterns. The binary also reads the Business Manager inbox (FetchUsersInboxJS), sends messages as stolen pages (SendPageMessageWithApiKeyJS), modifies post privacy (SetPostPrivacyJS via CometPrivacySelectorSavePrivacyMutation), and publishes Reels through a four-step upload pipeline. All API calls target graph.facebook.com/v23.0, business.facebook.com, adsmanager.facebook.com, and vupload-edge.facebook.com.
Stolen sessions persist to .fb_sessions.json in the user’s home directory, encrypted with ChaCha20-Poly1305 AEAD via a SecureHiddenStorage layer that also uses RC4 and a custom Base64 encoding for key material. Anti-tamper checks refuse operations when the encryption key has changed or data integrity fails. Quota data is cached separately in .q.dat and .n8n_q_cache. The binary manages a full session lifecycle: creation, retrieval by type and by ID, refresh via cookie rotation (RefreshFacebookSessionJS), and bulk clearing.
rup.js imports child_process.execFile, writes a buffer to a temp file in os.tmpdir(), executes it, and cleans up with fs.unlinkSync. The export is named uploadReelFb, framing it as video processing, but the capability is unconstrained: the WASM binary can trigger arbitrary command execution on the host.
debug-auth.js exports validateDebugAuthKey. It splits an input into a timestamp and signature, computes HMAC with a hardcoded secret (six concatenated obfuscated fragments), and verifies via crypto.timingSafeEqual. Keys are valid for 60 seconds. This provides the operator a time-limited authenticated backdoor.
The campaign
The quota server is a Cloudflare Workers endpoint at hxxps://quota-service-worker[.]kerituni123[.]workers[.]dev, contacted via the /get-and-save path using a dedicated SimpleHTTPClient separate from the Facebook-facing HTTP client. HandleApiKeyAndQuotaCheck fires before every Facebook API operation. The binary sends a userId and receives an APIKeyInfo struct containing apiKey, teamId, deviceId, permissions, and lastSyncTime. ProcessQuotaCheckAndIncrement increments a usage counter before allowing each action. When the counter exceeds the plan limit: “Quota limit exceeded: Used %d/%d requests. Please upgrade your plan.”
Team-based licensing ("Invalid API key for user %s team %s"), per-device tracking, and a permissions field for feature gating are not features a lone attacker builds. The n8n community node is a distribution channel for a credential-harvesting operation that sells tiered access to compromised Facebook Business accounts. The proxy agent dependencies allow operators or their customers to route API calls through rotating proxies, reducing the chance that Facebook ties the traffic to a single origin.
Why the operation matters here
Removing n8n-nodes-social-facebook from the registry takes out one delivery vehicle. The operator’s Go WASM codebase, quota server, and proxy infrastructure remain intact for repackaging. The Go build ID, the gowasm module path, and the quota protocol are stable selectors for the operation’s tooling across future artifacts under different names.
| Indicator | Value |
|---|---|
| Package | n8n-nodes-social-facebook v0.2.0 |
| npm account | kerituni12 |
| npm shasum | e78a3aa89bcbac6408bb8c0a7902f8d7efa80e44 |
| GitHub org | botzvn |
| C2 endpoint | hxxps://quota-service-worker[.]kerituni123[.]workers[.]dev |
| C2 path | /get-and-save |
| WASM binary | dist/main.we (8,051,620 bytes, renamed .wasm) |
| SHA-256 (main.we) | 9e4c888c36a9c8e5da7958f5cccb2672849a90939af85d1993db206004ecaa29 |
| SHA-256 (we.js) | e4a80ec115a5fcb9df46b8327b2cbb57c62d86b3e7867ac8ea2185cf130d25bc |
| SHA-256 (init.js) | 17d055dfeec498d32a54c417a8c7b87164da295958fa9c6afdefd28ab00bda3d |
| SHA-256 (debug-auth.js) | 6c5dd915295d8890ee0089e572322cf58b2588dbd9d9d90d997f593679201454 |
| Go build ID | TidBu8BKCLbD4fWIrrkT/Dyk0hepIo_ucc0Jc1kdm/VVeUmeTqF0L4USntkCxN/EaJ86auSW9yFT3VECzM9 |
| VCS revision | 7acabc12f2975c6c0ba5831ad8c12fbca7c260e2 |
| Go module | gowasm (7 subpackages, 36 source files) |
| Session file | ~/.fb_sessions.json |
| Quota files | ~/.q.dat, ~/.n8n_q_cache |
| Token regex (user) | window\.__accessToken\s*=\s*"(EAAB[^"]+)" |
| Token regex (ads) | \["(EAAG\w+) |
| DTSG regex | "DTSGInitialData",\[\],\{[\s\S]*?"token":"([^"]+)" |
| Targeted API | graph.facebook.com/v23.0, business.facebook.com, adsmanager.facebook.com, vupload-edge.facebook.com |
| Proxy deps | socks-proxy-agent, https-proxy-agent |
What a defender can do
Uninstall n8n-nodes-social-facebook and delete any dist/main.we file on the host. Check for and remove .fb_sessions.json, .q.dat, and .n8n_q_cache from every home directory on n8n runner machines. Revoke all Facebook user, page, and ads access tokens from Meta Business Settings, then rotate any credentials stored in n8n’s credential manager for Facebook integrations. Audit installed n8n community nodes for WASM binaries, .we files, or gulp-javascript-obfuscator in their dependency trees. None of these steps reveal whether other packages from the same operation are already installed under a different name.
Where Aephix fits
The build ID and quota protocol that identify this operation’s tooling can reappear in unrelated package names. Before you install a community node or connect to any automation server, Aephix Vantage gives you a free, cross-ecosystem view of what is already known to be malicious, so a package with a hostile history is visible before it reaches your workflow runner. Every week, Weekly Sleuth reports the malicious packages, models, skills, MCP servers, extensions, and containers confirmed that week alongside the wider operations behind them, with a confidence level and supporting evidence, so subscribers act against the operation rather than the single artifact.