A backdoor was hidden inside dbgpkg, a PyPI package presented as a "Python Debugging Toolkit." Armando discovered that every version of dbgpkg ever published to PyPI -- 1.3.6, 1.3.7, and 1.3.8 -- contained malicious code, making this a purpose-built attack rather than a compromised legitimate project. Version 1.3.8, published on May 13, 2025, delivers an import-time reverse shell using gsocket and exfiltrates host data through Pastebin. The package has since been removed from PyPI, but not before accumulating 439 downloads.
Key Findings
- Malicious version: v1.3.8, published 2025-05-13; no clean predecessor exists -- all three published versions are malicious
- Entry point: install and build lifecycle hooks in setup.py and pyproject.toml trigger automatically on pip install
- Targets: Linux -- downloads and installs a gsocket reverse shell (gs-netcat) and exfiltrates the binary path to Pastebin
- Evasion: checks for a sentinel file (/lib/systemd/system/defunct.dat) before executing payload, preventing re-execution on the same host
- Detection: Script-Python.Backdoor.SupplyChain, Archive-ZIP.Backdoor.SupplyChain, Archive-GZIP.Backdoor.SupplyChain, Archive-TAR.Backdoor.SupplyChain, Text.Backdoor.SupplyChain
Package Background
dbgpkg was published to PyPI on May 13, 2025, under the description "Python Debugging Toolkit." It carries no source code repository link and declares no meaningful homepage, two red flags that distinguish purpose-built attack packages from legitimate open source projects. The package was published by the account Lukasa (me@lukasa.org) -- the same account linked to 24 PyPI packages in total, including names that impersonate well-known Python HTTP libraries: requests, certifi, h2, hpack, hyper, wsproto, brotlipy, and others. Despite amassing 439 downloads across its three versions, dbgpkg has zero direct imports in downstream public packages, consistent with a campaign targeting developer machines and CI/CD pipelines rather than an established library ecosystem.
Attack Analysis
The attack is unconventional in one respect: the malicious payload lives not in an install script that runs once, but in the package's __init__.py -- meaning it executes on every Python import of dbgpkg, not only at install time. The install and build hooks defined in setup.py and pyproject.toml act as the declared entry points that trigger on pip install, but the real payload is loaded each time any code does import dbgpkg.
The 1.3.8 version introduces a meaningful evasion step absent in its predecessors. Before doing anything, the code checks whether the file /lib/systemd/system/defunct.dat exists on the host. If the sentinel is present, the payload silently exits -- this prevents the backdoor from re-running on a host it has already compromised, reducing the operational footprint and the chance of detection through repeated anomalous network connections.
If the sentinel is absent, the attack proceeds in three steps. First, it fetches an RSA public key from Pastebin using the API endpoint at https://pastebin.com/api/api_post.php. Second, it downloads and executes the gsocket reverse shell installer from https://gsocket.io/y -- a legitimate network tunneling tool repurposed as a backdoor delivery mechanism. Third, it encrypts the path to the installed gs-netcat binary and exfiltrates it back to Pastebin, giving the attacker a record of which hosts are now accessible via the reverse shell tunnel.
The progression from 1.3.6 to 1.3.8 shows deliberate development: each version carries the same Proxy-class backdoor structure, with 1.3.8 adding the sentinel check as an operational improvement. This is not a smash-and-grab -- the attacker invested time refining the implant across three rapid releases on the same day.
Malicious Files
__init__.py is the core backdoor. It implements an import-time payload using a Proxy class, identical in structure to the 1.3.7 version but with the added sentinel file check. On a fresh host (no /lib/systemd/system/defunct.dat), it fetches an RSA public key from Pastebin, downloads and runs the gsocket reverse shell from https://gsocket.io/y, encrypts the gs-netcat binary path, and exfiltrates it to Pastebin. The sentinel mechanism prevents re-execution on the same host after the first successful compromise.
setup.py declares the install lifecycle hook, ensuring that pip install dbgpkg triggers the malicious chain. Armando flagged it as a container of malicious content: it pulls in the same PKG-INFO and __init__.py that carry the backdoor logic.
pyproject.toml declares the build lifecycle hook and is likewise a container of the malicious content. Together with setup.py, it ensures the attack fires through both the modern (PEP 517) and legacy pip install paths.
dbgpkg-1.3.8-py3-none-any.whl (Archive-ZIP.Backdoor.SupplyChain) is the wheel distribution carrying the backdoor. The whl is a ZIP archive containing the malicious __init__.py and PKG-INFO directly.
dbgpkg-1.3.8.tar.gz (Archive-GZIP.Backdoor.SupplyChain) and dbgpkg-1.3.8.tar (Archive-TAR.Backdoor.SupplyChain) are the sdist distributions, both containing the same malicious payload in src/dbgpkg/__init__.py.
Recommendations
Developers and security teams should take the following steps:
- Identify exposure: Check whether dbgpkg v1.3.8 (or any version) appears in your dependency tree, including transitive dependencies. Any pipeline that ran
pip install while this version was current should be considered potentially affected.
- Update immediately: Remove dbgpkg entirely -- no clean version exists. The package has been removed from PyPI, but local caches and lockfiles may still reference it.
- Inspect affected systems: On machines that installed the malicious version, check for the gs-netcat process, the sentinel file at /lib/systemd/system/defunct.dat, and any unexpected outbound connections to gsocket.io or pastebin.com.
- Audit the publisher account: The Lukasa account on PyPI published 24 packages, many impersonating well-known HTTP libraries. Review whether any other packages from this account appear in your dependency trees.
- Scan your software supply chain: Use Spectra Assure Community (https://secure.software/pypi/packages/dbgpkg) to check whether packages in your environment have been flagged.
Indicators of Compromise
Malicious Files
| Filename | SHA256 | Detection |
|---|
| dbgpkg-1.3.8-py3-none-any.whl | 1ca2a46219b9dd0499ecf8d19bb68b503695aa5f0fb8fb9f0d47fdfd860ee969 | Archive-ZIP.Backdoor.SupplyChain |
| PKG-INFO | 3caf06aefeee6b3371b3fa8898b5d7d23ff0daf140a31fae00c7555f2e97782a | Text.Backdoor.SupplyChain |
| init.py | d800eab5a4fed54d8a58432e862d896f7338b4a3911e7571d7ac1d1463998601 | Script-Python.Backdoor.SupplyChain |
| setup.py | 98e50fe2d8a965caec97ff61f1142bc8fc0ac9fec693afe0bb7e687ca6065f96 | Script-Python.Backdoor.SupplyChain |
| pyproject.toml | b300606bbda19a52b92b529ce93e65736e5d6cecadf133d6882a918b30de6dd7 | Text.Backdoor.SupplyChain |
Network IOCs
| URL / IP | Purpose |
|---|
| https://pastebin.com/api/api_post.php | Fetch RSA public key; exfiltrate encrypted gs-netcat binary path |
| https://gsocket.io/y | Download and install gsocket reverse shell (gs-netcat) |
Archive Hashes
| File | SHA256 |
|---|
| dbgpkg-1.3.8.tar.gz | f233ea9ba0e0509f842bed991efd7a2e797dbb9bedfe3c7bd57416becbcdaa58 |
| dbgpkg-1.3.8.tar | 021f6239c4c012135a9e03f887fbccf5d090f631aa0079e9f25d8634759d6fe7 |