aiocpa added credential theft inside a published distribution
PyPI removed aiocpa after finding obfuscated code that replaced its client constructor. The linked source repository lacked the payload, making the distribution itself the relevant object of investigation.
A source repository can look like a useful maintained project while its published distribution contains additional code. PyPI's November 25 analysis of aiocpa documents that discrepancy. The registry removed the project after investigating an obfuscated payload that stole Crypto Pay client arguments through a Telegram endpoint. Its linked repository did not contain the obfuscated code found in the package.
The analysis identifies versions 0.1.13 and 0.1.14 as containing the payload. It also distinguishes the distribution name aiocpa from the installed module name cryptopay. That internal name does not identify the separate PyPI project also named cryptopay. Keeping those names distinct is necessary for interpreting an installation inventory without accusing an unrelated package of the same behavior.
I use Python largely because of what its libraries make available. That dependence makes the installable distribution the object that matters when assessing an application's code. A repository is useful evidence about development, but it cannot substitute for the bytes the package installer obtains. This incident provides a concrete example of why the distinction affects more than theoretical provenance discussions.
Importing a module runs its top-level code
Python's release-tagged import reference describes module execution as part of loading. The loader executes the code in the module's namespace. Import is therefore capable of installing behavior, not merely making a set of declarations available for later inspection. A package's initialization path can change objects that application code will subsequently use.
That mechanism is relevant to this payload. PyPI's analysis shows a replacement for CryptoPay.__init__ that calls the original constructor and then attempts to send its arguments to the remote endpoint. The replacement suppresses exceptions from that attempt. The program can consequently continue its normal initialization path while the wrapper adds another use of the arguments supplied to it.
Preserving the original call is part of what makes this modification consequential. Application code can receive the expected client object without an obvious failure directing attention to the added behavior. The sensitive arguments have already reached code executing in the same process. A library entrusted with a credential has access to that credential regardless of whether its documented purpose is legitimate.
The network destination identifies where the wrapper tries to send the information. It does not establish what happened afterwards. PyPI states that it does not know whether the exposed credentials were used. Exfiltration capability, a particular execution of that capability, and subsequent misuse are different claims. The public analysis supports the behavior of the code without providing an account of every affected installation.
Distribution formats create a separate review target
PEP 517 distinguishes a source tree from a source distribution and a built wheel. A source distribution is an archived release input. A backend can build a wheel through a standard interface for installation tooling. The existence of these steps means that the repository and the final installed files are related through a process, rather than being identical objects by definition.
Many differences between those objects are legitimate. Generated code and compiled extensions need not appear as identical files in a development tree. That legitimate flexibility is why a simple assumption of equality is insufficient. Determining whether a difference is expected requires understanding what the build should produce and comparing that expectation with the distributed artifact.
The aiocpa finding is especially clear because the suspicious behavior is relevant to the package's credential-handling path. A client library needs authentication arguments to perform its advertised work. A wrapper that forwards those arguments to a separate destination adds behavior outside that purpose. The useful evidence is the code implementing that forwarding, not the appearance of documentation or a source-hosting profile.
Obfuscation complicates inspection because the visible block does not present the final operation directly. Decoding it allows the investigator to connect the stored payload to its runtime behavior. That is different work from recognizing that a large encoded string looks unusual. A removal decision benefits from an explanation of what the decoded code does and where execution reaches it.
PyPI's earlier malware reporting announcement asks reporters for a reason and an Inspector link to specific files or lines. That format supports this distinction between suspicion and evidence. A reviewer can begin with the identified behavior instead of reconstructing which part of a distribution prompted the report.
Publication identity is a different question from safety
Earlier this month, PyPI announced digital attestation support. The service can associate a distribution with an upstream repository, workflow, and commit through signed identity-based statements. It verifies attestations when accepting them and provides access through an Integrity API and per-file pages. Those mechanisms provide evidence about publication identity that plain project metadata does not establish.
That is useful evidence, but its meaning remains specific. Knowing which workflow uploaded a file does not prove that every operation in the file is acceptable. A workflow can publish exactly the artifact its operator intended while that artifact contains malicious behavior. Conversely, a discrepancy between reviewed source and a distribution asks what happened during publication. The correct investigation depends on which of those claims the evidence supports.
I regard stronger publication identity as a worthwhile improvement because it gives consumers more facts to examine. It cannot replace the judgment about whether the package's behavior is appropriate. Python's packaging systems already contain enough separate concepts that their security properties need precise descriptions. An attestation establishes a relationship, while code analysis establishes what the related artifact can do.
For this incident, the report ties a malicious constructor wrapper to specific releases and records removal of the project. Consumers investigating prior use need to preserve the distinction between its distribution and module names. The relevant behavior occurs when the library's import path installs the wrapper and client initialization passes arguments through it. PyPI's uncertainty about subsequent credential use remains part of the published finding, even though the exfiltration behavior is visible in the decoded code.