The JFrog security research team recently identified a supply chain attack targeting the xinference package on PyPI. Versions 2.6.0, 2.6.1, and 2.6.2 were compromised and yanked by maintainers after users reported suspicious behavior. If you installed or imported these versions, you must assume your environment is compromised.
This is the latest hit in an ongoing multi-ecosystem campaign by the threat actor tracked as TeamPCP, who have recently compromised PyPI packages including litellm and telnyx, as well as npm, Go, OpenVSX, and GitHub repositories. The same actor marker, payload structure, and targeting profile tie this incident directly to that campaign.
TeamPCP's established pattern on PyPI involves hijacking legitimate packages by injecting a base64-encoded payload into a core module, triggering secret harvesting on import, and exfiltrating the results to attacker-controlled infrastructure. The xinference compromise follows this exact model.

This is not a typo-squat or a fake package. The attackers hijacked the legitimate xinference release line and published trojanized versions directly to PyPI. The malicious code lives inside xinference/__init__.py, which means it runs the moment you import the package. That includes import xinference, CLI startup, service startup, and any downstream library that resolves the package version.
We recovered a base64 payload embedded in the file. It is passed straight into a detached subprocess.Popen call that spawns a new Python interpreter, suppresses stdout and stderr, and executes the decoded content in the background. This design hides the malware from the main application process.
The decoded payload opens with the comment # hacked by teampcp, the same actor marker seen in recent TeamPCP compromises.
The decoded first stage is a short Python script that starts with the comment # hacked by teampcp. It contains a second embedded base64 block and a start() function that does the following:
- Creates a temporary directory.
- Decodes the second-stage collector.
- Pipes it into a child Python interpreter via stdin.
- Captures the child’s stdout into a temporary file named
f. - Compresses
fintolove.tar.gz. - Uploads the archive to
hxxps[:]//whereisitat[.]lucyatemysuperbox[.]space/usingcurl.
The exfiltration request uses a POST with --data-binary, sets the custom header X-QT-SR: 14, and suppresses all error output. Temporary files are cleaned up automatically when the context manager exits.
The second stage is the actual collector. It defines helpers to read files, glob patterns, run shell commands, and walk directories with a depth limit. Everything it collects is written to stdout, which stage 1 turns into the exfiltrated tarball.
The collector begins by profiling the host:
run('hostname; pwd; whoami; uname -a; ip addr 2>/dev/null || ifconfig 2>/dev/null; ip route 2>/dev/null')
run('printenv')
It then targets secrets typically found on Linux servers, cloud VMs, CI runners, and inference hosts. The list is extensive:
- SSH private keys and host keys (
/.ssh/id_rsa,/etc/ssh/ssh_host_*_key) - Git credentials (
/.git-credentials,/.gitconfig) - AWS credentials (
/.aws/credentials,/.aws/config, IMDS role tokens) - Kubernetes configs and service account tokens (
/.kube/config,/var/run/secrets/kubernetes.io/serviceaccount/token) - Docker registry auth (
/.docker/config.json) - Package manager tokens (
/.npmrc,/.pypirc,/.cargo/credentials.toml) - Environment files (
.env,.env.local,.env.production, and recursive.envsearches) - Database and mail configs (
.pgpass,.my.cnf,redis.conf,postfix sasl_passwd) - VPN and infrastructure material (WireGuard configs, Helm data,
terraform.tfvars,terraform.tfstate) - TLS private keys (
.pem,.key,.p12,.pfx) - Cryptocurrency wallets (Bitcoin, Ethereum, Solana, Monero, Cardano, and others)
- Local account data (
/etc/passwd,/etc/shadow, auth logs)
The GitHub issue that triggered the incident reported grep activity related to passwords. That matches the collector exactly. The payload runs greps for Slack and Discord webhooks, API keys across .env and .json files, and RPC credentials under /root and /home.
The malware does more than read static files. It includes AWS-aware logic that attempts IMDSv2 token retrieval, harvests IAM role credentials from the instance metadata service, and constructs SigV4-signed API requests for secretsmanager.ListSecrets and ssm.DescribeParameters.
We also noted a bug in the sample: the loop around GetSecretValue assigns a secret ID variable but never uses it in the request payload. Even with that flaw, the intent is clear. The attacker is actively targeting cloud-hosted victims and can recover environment credentials, IMDS role credentials, and secret inventory metadata at minimum.
The sample uses a few reliable stealth techniques. It runs in a background process detached from the import path. It suppresses stdout and stderr. It wraps actions in broad exception handlers so a missing file or failed command does not crash the script. It limits recursion depth to keep scans bounded and collects only regular files.
The xinference payload is structurally similar to the TeamPCP compromises we analyzed in litellm and telnyx, but it is a lighter variant with notable differences:
| Feature | litellm / telnyx |
xinference |
|---|---|---|
| Trigger | Import or .pth execution |
Package import only |
| Encryption | AES-256-CBC + RSA-4096 envelope | None (plaintext tarball) |
| Exfil header | X-Filename: tpcp.tar.gz |
X-QT-SR: 14 |
| Archive name | tpcp.tar.gz |
love.tar.gz |
| Persistence | systemd user service (sysmon/audiomon), K8s privileged pod deployment |
None |
| Actor marker | # hacked by teampcp |
# hacked by teampcp |
| C2 domain | models[.]litellm[.]cloud, 83[.]142[.]209[.]203 |
whereisitat[.]lucyatemysuperbox[.]space |
The absence of encryption and persistence suggests either a shift in TTPs or an earlier-stage payload designed for rapid credential exfiltration rather than long-term host control. The custom header X-QT-SR: 14 and archive name love.tar.gz are deviations from the established tpcp.tar.gz pattern, but the underlying collector logic and target list remain consistent with TeamPCP's known tooling.
While the exact publish vector for xinference is unconfirmed, TeamPCP's recent PyPI compromises have followed a consistent pattern: stealing CI/CD or maintainer credentials (often via compromised upstream tools such as Trivy) and using them to publish trojanized releases. The xinference maintainers have acknowledged an active attack and yanked the affected versions, which aligns with this model.
The absence of a backdoor or persistence mechanism is notable. There is no ransomware, no destructive wiping, no explicit persistence, no reverse shell, and no privilege escalation. This is a pure import-triggered recon and credential exfiltration payload. It wants your secrets, not your compute.
If you installed or ran xinference versions 2.6.0 through 2.6.2, treat the host as compromised. Take these steps immediately.
Isolate affected hosts from sensitive networks. Check for outbound traffic or DNS lookups to whereisitat[.]lucyatemysuperbox[.]space. Any host that imported the package may have leaked data.
You must assume every secret on the machine is at risk. Rotate the following:
- SSH private keys
- Cloud credentials and tokens (AWS, GCP, Azure)
- Kubernetes service account tokens and cluster configs
- Docker registry credentials
- PyPI, npm, and Cargo publishing tokens
- Database passwords and
.envsecrets - TLS private keys and certificates
- CI/CD deployment state and Terraform files
- Blockchain wallet keys and seed material
Review AWS CloudTrail, Kubernetes audit logs, Git hosting logs, and registry activity for unauthorized access. Check shell history and auth logs to bound the exposure window.
Remove the compromised package. Because the payload does not install persistence, simply removing the package stops future execution on that specific import. However, the safest approach is to rebuild the environment from a trusted baseline rather than attempting piecemeal cleanup. Reinstall xinference from a known clean version (any release before 2.6.0 or after the maintainer's subsequent fix).
pip uninstall xinference
pip cache purge
# Reinstall from a verified clean version
pip install xinference==<safe_version>
| Package Name | Malicious Versions | Xray ID |
|---|---|---|
xinference |
2.6.0, 2.6.1, 2.6.2 | XRAY-96896 |
This incident is another chapter in TeamPCP's ongoing supply chain campaign. The attackers continue to target high-value AI and infrastructure packages across ecosystems, understanding that these environments are rich with cloud credentials, API keys, and deployment secrets. The payload's file paths and AWS logic strongly suggest the operator tailored the attack for AI infrastructure and CI/CD runners.
As we have seen with litellm, telnyx, and now xinference, this campaign is not isolated and is likely to continue. Users must remain cautious with supply chain updates, especially for packages in the AI and infrastructure space.
If you touched the affected versions, act now. Rotate secrets, audit logs, and rebuild from a clean baseline. JFrog Xray and JFrog Curation provide detection for malicious packages to prevent these releases from entering your supply chain in the first place.
This package is already detected by JFrog Xray and JFrog Curation under the Xray ID listed above.
xinference-2.6.0xinference-2.6.1xinference-2.6.2
- Domain:
whereisitat[.]lucyatemysuperbox[.]space - URL:
hxxps[:]//whereisitat[.]lucyatemysuperbox[.]space/ - Custom HTTP header:
X-QT-SR: 14
xinference/__init__.py, SHA-256:e1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127- Decoded stage 1, SHA-256:
077d49fa708f498969d7cdffe701eb64675baaa4968ded9bd97a4936dd56c21c - Decoded stage 2, SHA-256:
fe17e2ea4012d07d90ecb7793c1b0593a6138d25a9393192263e751660ec3cd0 - Temporary archive name:
love.tar.gz - Actor marker string:
# hacked by teampcp