WeOwnAiAgents-Hackerhouse/WeOwnAiAgent is a single-commit GitHub repository presenting an ElizaOS-based AI agent with a Next.js chatbot frontend. The functional code is clean. postcss.config.mjs appends 4,785 bytes of obfuscated JavaScript after 507 bytes of whitespace on the final line. The payload sets campaign marker 9-1186-2 and executes code through a two-layer Function constructor chain. Next.js loads postcss.config.mjs at build time, triggering the payload during next build or postcss globals.css. The 507-byte whitespace padding matches the exact count observed in five prior specimens linked to the Ethereum blockchain C2 operation.
The artifact
The repository contains a single commit (da43373, Feb 26, 2025) by the handle malikdhruv007. The commit message reads “WIP: adding initial version webpage and application (will be replaced by the vercel ai chatbot on the master branch).” Feb 2025 predates every other specimen linked to this operation by over a year.
package.json names the project we-own-ai-agent-creatorbox at version 0.1.9. The dependency list splits into two stacks: an ElizaOS agent backend (@elizaos/core, @elizaos/plugin-bootstrap, @elizaos/plugin-node, @elizaos/plugin-solana, @elizaos/plugin-story, and six more ElizaOS packages) and a Next.js 15 chatbot frontend (Vercel AI SDK, Radix UI, Tailwind CSS 4, shadcn/ui components). src/index.ts bootstraps the ElizaOS runtime with database, cache, and plugin initialization. characters/eliza.character.json defines a crypto-IRA advisor persona. The frontend is a standard Vercel AI chatbot scaffold with model selection, chat input, and artifact display. All of this is functional, unremarkable code.
Two text files inflate the repository. src/l2beat-l2beat.git.txt (78 MB, 1.6 million lines) is a directory tree dump of the l2beat blockchain analytics project. vercel-ai-chatbot.git.txt (728 KB, 23,697 lines) is a directory tree dump of the Vercel AI chatbot template. Neither file is referenced by any import or build configuration. They add bulk.
What it does
postcss.config.mjs is 5,571 bytes. Lines 1 through 13 configure Tailwind CSS and Autoprefixer, standard for a Next.js project:
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
'@tailwindcss/postcss': { },
},
};
export default config;
Line 14 begins with export default config; (a duplicate of line 13’s export, making the first export dead code). After the semicolon: 507 bytes of ASCII space characters (0x20), then the payload.
The payload structure
The obfuscated JavaScript on line 14 proceeds in three stages.
Stage 1: campaign marker and globals. global['!']='9-1186-2' sets the campaign identifier. A character-shuffling function (_$_1e42) decodes three strings from the seed "rmcej%otb%" with key 2857687, producing ['r', 'object', 'm']. The payload then sets global.r = require and global.m = module, making Node.js built-ins available to later stages without referencing require or module by name.
Stage 2: Function constructor. A second character-shuffling function (sfL, seed 2667686) decodes the string "wuqktamceigynzbosdctpusocrjhrflovnxrt" to extract the property name constructor. Accessing sfL.constructor returns the Function built-in. The payload uses it to construct a new function from a 566-character body (decoded from the scrambled joW variable) that implements an argument decoder using a permutation array of 20 character codes.
Stage 3: encoded execution. The argument decoder processes a 2,117-character scrambled string (decoded from the pYd variable) with a numeric key (2509). The two-layer obfuscation (character shuffling plus argument encoding) prevents static extraction of the final executed code. The obfuscation style differs from the _0x hex-index pattern used in the blockchain C2 payloads of local-mcp, animotion-mcp, and expo-mcp.
package.json defines "build:css": "postcss globals.css -o output.css", which directly invokes PostCSS and loads the configuration file. "build": "next build" and "dev": "next dev" also load PostCSS configuration at startup. Running any build or development command triggers the payload.
The campaign
The 507-byte whitespace padding appears in six confirmed specimens: agentgui (A9-2057), expo-mcp (A9-2353-1), animotion-mcp (A9-4051-1), local-mcp (A10-*050), stitch-mcp (A11—*), and now WeOwnAiAgent (9-1186-2). The byte count is identical across all six. The campaign identifier prefix 9- in this specimen differs from the A9-/A10-/A11- numbering used in the others.
The PostCSS configuration attack vector is the same mechanism used by stitch-mcp: both hide the payload on a trailing line of postcss.config.mjs, and both rely on Next.js loading that file automatically. stitch-mcp used the _0x hex-index obfuscation pattern and carried the blockchain C2 loader directly. WeOwnAiAgent uses a different obfuscation style (character-shuffling with Function constructor) and a different campaign identifier format. The two-layer encoding in this specimen prevents static extraction of the final executed code, so the presence or absence of the blockchain C2 loader, Ethereum wallet, and RPC infrastructure cannot be confirmed without execution.
The commit date (Feb 26, 2025) predates all other known specimens by more than a year. The other specimens were committed between July and September 2026. Whether this date is authentic, backdated by a force-push, or manipulated cannot be determined from a single commit.
Why the operation matters here
The payload hides on a single line of a file that every Next.js developer expects to exist and has no reason to inspect character by character. postcss.config.mjs ships in project templates and is loaded silently by the framework. The 13 lines above the payload are valid. Opening the file shows a normal PostCSS configuration with a long line 14 that, at default zoom, looks like trailing whitespace. The 78 MB l2beat-l2beat.git.txt file pushes postcss.config.mjs further down the file listing during a repository review.
What a defender can do
- Scan build-time configuration files (
postcss.config.mjs,next.config.mjs,tailwind.config.js) for lines exceeding a reasonable length (the payload line is 5,313 characters) - Flag any JavaScript file where the last line is substantially longer than every other line
- Reject repositories containing multi-megabyte text files that are not referenced by any import or build script
- Review the
scriptssection ofpackage.jsonfor PostCSS CLI invocations (postcss globals.css -o output.css) that would trigger configuration loading
Where Aephix fits
Six specimens with three delivery mechanisms share the same 507-byte padding. Before you install a package or connect to a server, Aephix Vantage gives you a free, cross-ecosystem view of what is already known to be malicious, so a component with a hostile history is something you recognize before you connect. Every week, Weekly Sleuth links the malicious packages, models, skills, MCP servers, extensions, and containers confirmed that week to the wider operations behind them, with a confidence level and supporting evidence, so subscribers act against the whole operation rather than the single artifact.
Indicators of compromise
| Indicator | Type |
|---|---|
WeOwnAiAgents-Hackerhouse/WeOwnAiAgent | Repository |
malikdhruv007 | Git handle |
da43373 | Commit SHA |
9-1186-2 | Campaign ID |
postcss.config.mjs line 14 (5,313 chars) | Payload location |
| 507-byte whitespace padding (0x20) | Shared signature |
sfL.constructor → Function | Obfuscation technique |
global.r = require, global.m = module | Runtime alias pattern |
src/l2beat-l2beat.git.txt (78 MB, not imported) | Repository padding |
vercel-ai-chatbot.git.txt (728 KB, not imported) | Repository padding |