CVE
Not assigned
CWE
CWE-506
Affected Surface
- PyPI package reqcrypts versions 0.1.0, 0.1.1, 0.1.2, and 0.1.3
- Related August 2026 campaign packages reqcrypt 0.1.0 and requests-crypt 0.1.0
- Python applications and scripts that replaced requests-like clients with reqcrypts
- Developer workstations, CI runners, and internal tooling that contacted attacker-controlled or attacker-influenced HTTP endpoints through the affected package
reqcrypts is a good example of why “small helper library” should never be read as “small risk.” The package, published to PyPI in four versions late on 20 August and quarantined the next day, presented itself as an HTTP client. The dangerous behavior was not an install hook, a dropped binary, or a noisy second stage. It was the client itself.
Package analysis tied to the 21 August malware reporting shows that reqcrypts inspected JSON responses for a special field named _payload, base64-decoded its contents, and passed the result into Python exec(). If the application talked to an attacker-controlled server, a compromised upstream, or even a hostile network intermediary that could tamper with JSON responses, the package turned that response channel into code execution inside the caller’s Python process.
Affected packages
The directly affected package versions are:
reqcrypts==0.1.0reqcrypts==0.1.1reqcrypts==0.1.2reqcrypts==0.1.3
The same August 2026 backdoor pattern also appeared in related PyPI packages:
reqcrypt==0.1.0requests-crypt==0.1.0
Those sibling packages matter because they show this was not a one-off typo or a single bad upload. It was a cluster of Python HTTP-client lookalikes built around the same idea: hide a response-driven execution path behind an innocuous networking facade.
Timing and registry evidence
PyPI’s preserved release page for reqcrypts 0.1.2 gives the basic timeline:
- release date: 20 August 2026
- quarantine date: 21 August 2026
- uploader agent:
python-requests/2.28.2 - no Trusted Publishing
Public version history also shows how fast the actor iterated:
0.1.0at2026-08-20T23:15:47Z0.1.1at2026-08-20T23:29:27Z0.1.2at2026-08-20T23:35:31Z0.1.3at2026-08-20T23:39:07Z
That release cadence looks less like normal maintenance and more like a short publication burst intended to establish multiple installable variants before quarantine.
The backdoor path
The key point is that reqcrypts did not need a second process or a shell pipeline. The malicious logic lived inside the HTTP handling path itself.
Package analysis published alongside the malware record describes this flow:
reqcrypts.get(url)
-> RequestHandler processes the HTTP response
-> PayloadManager looks for a JSON field named _payload
-> base64 decode
-> exec() inside the caller's interpreter
-> remove the field from the response object
Two details stand out.
First, the execution sink is response-driven. That means the attacker does not need local access to the machine after installation. They only need influence over what the client receives from the network.
Second, the package reportedly removes the _payload field after processing it. That is a concealment move. If the application logs or forwards the response object later, the marker that triggered execution may already be gone.
Why this is worse than a normal malicious import
Many malicious packages execute once at install time or import time and then do their damage locally. reqcrypts is more flexible because it turns every future request into a potential code-delivery event.
That shifts the trust boundary:
- compromise can happen long after installation
- a server the client calls can decide when to deliver code
- a man-in-the-middle with response tampering capability can do the same
- the same package can behave quietly in one environment and actively in another
In other words, the package is not only malware. It is also a covert execution framework embedded in a library that looks like transport plumbing.
Extra helper APIs make the backdoor easier to control
The malware analysis also describes additional exported helpers:
add_payload(trigger, code)set_default_payload(code)enable_payloads
Those names matter because they show the execution path was not accidental glue code around a parser mistake. The package appears to have been designed to store and trigger arbitrary Python source under caller-controlled conditions. That is deliberate operator functionality, not a bug.
Why appsec teams should care
The obvious victims are developers who installed the package directly. The broader risk is internal tooling.
Python HTTP wrappers routinely end up in:
- build and release scripts
- secret rotation jobs
- deployment helpers
- internal API clients
- test harnesses
- ad hoc automation on developer laptops
If one of those paths swapped in reqcrypts, the attacker gained a place where remote JSON could cross directly into exec(). That is a dangerous fit for any environment that already holds tokens, cloud credentials, service secrets, or source-control access.
Detection and hunting
Start with dependency inventory:
rg -n 'reqcrypts|reqcrypt|requests-crypt' \
requirements.txt constraints.txt pyproject.toml poetry.lock uv.lock Pipfile Pipfile.lock
Then search local environments, caches, and build artifacts for the execution markers reported in the package analysis:
rg -n '_payload|add_payload|set_default_payload|enable_payloads|PayloadManager|RequestHandler|exec\\(' \
.venv venv site-packages build dist
Because the trigger is HTTP-response content, review logs and traces for systems that used the package against externally reachable endpoints, not just for hosts that installed it.
Response guidance
If reqcrypts was present in a real environment, do not limit the response to uninstalling it.
- Remove the package and rebuild the Python environment from a clean base.
- Review whether the package was ever exercised against untrusted or semi-trusted endpoints.
- Rotate credentials available to the process that used it, especially API tokens, cloud keys, CI secrets, and source-control credentials.
- Audit logs around the package’s active window for unexpected outbound behavior and suspicious application actions following HTTP responses.
- Block the package name in internal mirrors and dependency-approval workflows so it cannot re-enter through ad hoc tooling.
The lesson here is straightforward. A network client is already in a privileged position because it sits on the boundary between remote data and local execution context. reqcrypts abused that position directly. Instead of hiding in an install script, it put the backdoor where the package’s advertised purpose gave it the most cover: inside normal response handling.
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.