Skip to content

Remove obfuscated RCE payload from postcss.config.mjs and restore .gitignore - #1

Draft
kevpay wants to merge 1 commit into
mainfrom
claude/citizenwallet-malicious-cleanup-bubc6e
Draft

Remove obfuscated RCE payload from postcss.config.mjs and restore .gitignore#1
kevpay wants to merge 1 commit into
mainfrom
claude/citizenwallet-malicious-cleanup-bubc6e

Conversation

@kevpay

@kevpay kevpay commented Aug 28, 2026

Copy link
Copy Markdown

Summary

postcss.config.mjs carried an obfuscated JavaScript payload appended after the config, hidden behind a long run of spaces on the closing line so it sits off-screen in an editor. The attacker also prepended a createRequire shim to the top of the file so the payload could reach node:child_process from an ESM config.

.gitignore was rewritten by the same activity to delete the .env entry and add config.bat.

What the payload does

  • Resolves its C2 endpoint from the Ethereum blockchain (EtherHiding), reading the host from recent transactions of a hardcoded attacker-controlled address via public RPC endpoints and a Blockscout txlist API.
  • Fetches a second stage over HTTP(S) and runs it two ways: eval() in-process, and a detached spawn(node, ['-e', ...]) with stdio: 'ignore' and windowsHide, unref()'d so it outlives the parent.

postcss.config.mjs executes on every build and dev server start.

Provenance

The payload arrived in a141bdd ("fix missing promise", 2025-10-11) — one day after the repo was created — and was replaced with a newer, blockchain-C2 variant by 191cd0d ("remove polin rider", 2026-05-27), a commit intended as a cleanup that shipped a fresh payload instead. That points at the committing machine rather than CI.

Worth noting this repo is an example intended for others to copy, so anyone who cloned it may have executed the payload on their own machine.

Scope note

This PR cleans the current tip only; the payload remains reachable in history. Ten other org repositories carry the same campaign, and any credentials reachable from an affected machine or CI run should be treated as compromised.


Generated by Claude Code

…tignore

postcss.config.mjs carried an obfuscated JavaScript payload appended after the legitimate
config, hidden behind a long run of spaces on the closing line so it sits
off-screen in an editor. Restored to its pre-tampering content.

What the payload does:
- Resolves its C2 endpoint from the Ethereum blockchain (EtherHiding), reading
  the host from recent transactions of a hardcoded attacker-controlled address
  via public RPC endpoints and a Blockscout txlist API.
- Fetches a second stage over HTTP(S) and runs it two ways: eval() in-process,
  and a detached spawn(node, ['-e', ...]) with stdio 'ignore' and windowsHide,
  unref'd so it outlives the parent.

postcss.config.mjs executes_on_every_build_and_dev_server_start, so this ran on developer
machines and in CI.

.gitignore was rewritten by the same commit: line endings converted, the .env
entry deleted, and a config.bat entry added. Removing .env from .gitignore
stages local secrets to become committable. Restored to its pre-tampering
revision.

The payload first arrived in a141bdd_("fix_missing_promise",_2025-10-11),_and_was_replaced_with_a_newer_variant_by_191cd0d_("remove_polin_rider",_2026-05-27).
@kevpay
kevpay force-pushed the claude/citizenwallet-malicious-cleanup-bubc6e branch from 9a7cb33 to ad92127 Compare September 1, 2026 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants