Xinference PyPI 2.6.x Import-Time Credential Exfiltration

Suspected
Discovered Apr 22, 2026

JFrog reported that the legitimate PyPI package xinference shipped malicious versions 2.6.0, 2.6.1, and 2.6.2 with import-time code in xinference/__init__.py. The payload collected host and secret material into love[.]tar[.]gz and posted it to whereisitat[.]lucyatemysuperbox[.]space with header X-QT-SR: 14.

0
Affected Packages
5
Observables
2
Sources

Defender Action Panel

Triage this incident quickly

Check whether your environment installed affected software, copy the top IOCs, run the tested hunting script when available, then review remediation guidance.

Am I affected?
Review affected software below
Immediate action
Audit locks, CI runners, developer workstations, and credential exposure.
Hunting
Has hunting script
077d49fa708f498969d7cdffe701eb64675baaa4968ded9bd97a4936dd56c21c
fe17e2ea4012d07d90ecb7793c1b0593a6138d25a9393192263e751660ec3cd0
whereisitat[.]lucyatemysuperbox[.]space
e1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127
hXXps://whereisitat[.]lucyatemysuperbox[.]space/

Analysis

Executive Summary

JFrog reported a PyPI supply-chain compromise of the legitimate xinference package affecting versions 2.6.0, 2.6.1, and 2.6.2. The malicious code lived in xinference/__init__.py, so exposure requires installation plus Python import, CLI startup, service startup, or another path that loads the package [research.jfrog.com opens in a new tab].

The decoded payload created a temporary directory, ran a second-stage collector, captured output to a temporary file named f, compressed it into love.tar.gz, and uploaded it to https://whereisitat.lucyatemysuperbox.space/ using curl --data-binary and header X-QT-SR: 14 [research.jfrog.com opens in a new tab]. JFrog lists the package file hash, stage hashes, archive name, actor marker string, affected versions, and Xray ID XRAY-96896 [research.jfrog.com opens in a new tab].

Current PyPI release history shows 2.5.0 before 2.7.0; the malicious 2.6.x releases are no longer in the visible history. Use version selectors and package-cache evidence as the primary exposure proof, then use C2/domain/header/hash selectors to separate confirmed execution from presumed exposure [pypi.org opens in a new tab].

Key Facts

Event Type: legitimate PyPI package compromise

Ecosystem: PyPI

Package:

  • name: xinference
  • malicious_versions: 2.6.0,2.6.1,2.6.2
  • visible_current_pypi_gap: 2.5.0 to 2.7.0

Collection Window Utc:

  • start: 2026-04-22T00:00:00Z
  • end: 2026-04-23T23:59:59Z

Execution Trigger: Python import or service/CLI path loading xinference/init.py

Malicious File:

  • path: xinference/init.py
  • sha256: e1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127

Decoded Stage Hashes Sha256:

  • stage_1: 077d49fa708f498969d7cdffe701eb64675baaa4968ded9bd97a4936dd56c21c
  • stage_2: fe17e2ea4012d07d90ecb7793c1b0593a6138d25a9393192263e751660ec3cd0

Network Iocs:

  • whereisitat[.]lucyatemysuperbox[.]space
  • hxxps://whereisitat[.]lucyatemysuperbox[.]space/

Protocol Artifacts:

  • curl --data-binary
  • X-QT-SR: 14

File Artifacts:

  • love[.]tar[.]gz
  • f

Strings:

  • hacked by teampcp

Credentials At Risk:

  • environment variables
  • SSH keys
  • cloud credentials
  • Kubernetes tokens and configs
  • Docker registry credentials
  • PyPI/npm/Cargo publishing tokens
  • .env secrets
  • TLS private keys and certificates
  • database credentials
  • wallet keys and seed material

Evidence Assessment

  • confirmed: JFrog identified xinference versions 2.6.0, 2.6.1, and 2.6.2 as compromised and lists Xray ID XRAY-96896 [research.jfrog.com opens in a new tab].
  • confirmed: JFrog identified xinference/__init__.py as the malicious file, SHA-256 e1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127, and decoded stage SHA-256 values 077d49fa708f498969d7cdffe701eb64675baaa4968ded9bd97a4936dd56c21c and fe17e2ea4012d07d90ecb7793c1b0593a6138d25a9393192263e751660ec3cd0 [research.jfrog.com opens in a new tab].
  • confirmed: JFrog observed exfiltration to https://whereisitat.lucyatemysuperbox.space/, archive name love.tar.gz, and HTTP header X-QT-SR: 14 [research.jfrog.com opens in a new tab].
  • unclear: Public evidence does not prove the exact PyPI publish credential theft path. JFrog describes a likely path based on prior campaign patterns, but the specific initial access vector remains unconfirmed [research.jfrog.com opens in a new tab].
  • not_observed: JFrog states the payload does not include persistence, a reverse shell, destructive wiping, ransomware, or privilege escalation [research.jfrog.com opens in a new tab].

Impact Determination

Analysis table
ClassificationCriteriaEvidence to collectHandling decision
Confirmed compromisexinference==2.6.0, xinference==2.6.1, or xinference==2.6.2 was installed and import/runtime/C2 evidence exists.Installed package metadata, lockfile, package cache, Python import traces, xinference/__init__.py hash, love.tar.gz, C2 DNS/HTTP, X-QT-SR: 14, # hacked by teampcp.Preserve the host/container/runner evidence, isolate the asset, revoke credentials reachable from the Python process, and run the downstream audits below.
Presumed exposedAn affected version was installed in a host, image, notebook, virtualenv, or CI job, but import/network telemetry is missing.pip freeze, requirements*.txt, poetry.lock, uv.lock, image layer output, CI install output, package cache.Treat secret material readable by that environment as exposed unless import non-execution can be proven.
Potentially exposedxinference was unpinned or upgraded during the April 22-23 collection window, but resolved version evidence is incomplete.Dependency manifests, package proxy records, CI output, image build history, notebook environment exports.Collect resolver/cache evidence before reducing scope.
Not exposedEvidence shows no malicious 2.6.x version in source, lockfiles, package caches, images, hosts, or runtime telemetry.Negative dependency inventory, virtualenv/container search, package cache query, and network selector search.Keep negative evidence with the case record and close this event for that asset.
UnknownRequired package inventory, CI output, endpoint telemetry, image inventory, or network telemetry is unavailable.Named telemetry gap with system, owner, and retention status.Keep high-value AI/ML, GPU, CI, and cloud-adjacent assets in scope until evidence is recovered or risk is explicitly accepted.

Minimum Evidence To Collect

Package Evidence:

  • xinference==2.6.0
  • xinference==2.6.1
  • xinference==2.6.2
  • xinference/init.py SHA-256 e1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127

Runtime Evidence:

  • Python import of xinference
  • subprocess.Popen child Python execution
  • curl --data-binary

Network Evidence:

  • whereisitat[.]lucyatemysuperbox[.]space
  • hxxps://whereisitat[.]lucyatemysuperbox[.]space/
  • X-QT-SR: 14

File Evidence:

  • love[.]tar[.]gz
  • temporary collector output file named f

String Evidence:

  • hacked by teampcp

Timeline

  • 2026-04-22: JFrog published research identifying xinference versions 2.6.0, 2.6.1, and 2.6.2 as compromised and yanked [research.jfrog.com opens in a new tab].
  • 2026-04-22: JFrog described the malicious payload in xinference/__init__.py, including import-time execution and staged collection/exfiltration [research.jfrog.com opens in a new tab].
  • 2026-04-22: JFrog listed the IOCs: affected package versions, C2 domain/URL, header X-QT-SR: 14, SHA-256 hashes, archive love.tar.gz, and marker # hacked by teampcp [research.jfrog.com opens in a new tab].
  • 2026-04-25: PyPI visible release history resumed at 2.7.0 after 2.5.0, leaving the compromised 2.6.x releases absent from the current visible release list [pypi.org opens in a new tab].

What Happened

Attackers published malicious xinference versions directly to PyPI under the legitimate package name. JFrog reports that this was not a lookalike package; the affected identity was the real xinference package [research.jfrog.com opens in a new tab].

The malicious code was placed in xinference/__init__.py, making import and service startup the relevant execution boundary. The first stage decoded a second-stage collector, ran it in a child Python interpreter, wrote collected output to a temporary file named f, compressed that file into love.tar.gz, and uploaded the archive with curl to the C2 URL [research.jfrog.com opens in a new tab].

JFrog's decoded collector logic targeted host inventory and secret locations. The article specifically calls out SSH material, cloud credentials, Kubernetes service account tokens/configs, Docker registry credentials, package publishing tokens, .env secrets, TLS material, database passwords, and wallet key material as credential classes requiring downstream scoping [research.jfrog.com opens in a new tab].

Package Manipulation

Package Identity:

  • registry: PyPI
  • package: xinference
  • malicious_versions: 2.6.0,2.6.1,2.6.2

Malicious File:

  • path: xinference/init.py
  • sha256: e1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127

Execution Trigger: module import or startup path that imports xinference

Payload Behavior

The stage-one payload created temporary working storage, decoded and piped a second-stage collector into a child Python interpreter, captured stdout into f, compressed the output into love.tar.gz, and sent the archive using curl --data-binary [research.jfrog.com opens in a new tab].

Exfiltration

Exfiltration:

  • domain: whereisitat[.]lucyatemysuperbox[.]space
  • url: hxxps://whereisitat[.]lucyatemysuperbox[.]space/
  • method: HTTP POST
  • tool: curl
  • body_mode: --data-binary
  • custom_header: X-QT-SR: 14
  • archive: love[.]tar[.]gz

Affected Assets and Blast Radius

Affected Assets:

  • ecosystems: PyPI
  • packages: xinference==2.6.0,xinference==2.6.1,xinference==2.6.2
  • environments: developer virtualenvs,Jupyter notebook kernels,GPU inference servers,CI runners,container images built from affected requirements,Kubernetes pods importing xinference
  • downstream_systems: AWS,GCP,Azure,Kubernetes,Docker registries,PyPI/npm/Cargo registries,Git hosting

Not Currently Known To Affect:

  • visible PyPI releases 2.5.0 and 2.7.0 when installed from official current metadata

Indicators of Compromise

The following indicators of compromise (IOCs) can be used to scope exposure across local repositories, systems, and telemetry exports:

Hashes

  • e1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127
  • 077d49fa708f498969d7cdffe701eb64675baaa4968ded9bd97a4936dd56c21c
  • fe17e2ea4012d07d90ecb7793c1b0593a6138d25a9393192263e751660ec3cd0

Domains

  • whereisitat.lucyatemysuperbox.space

Urls

  • hxxps://whereisitat[.]lucyatemysuperbox[.]space/

Downstream Abuse Audits

Compromised workstations expose active API credentials, requiring immediate rotated revocation. The following platforms are at risk:

  • GitHub OIDC and PATs: Attackers harvested SSH private keys and Git Personal Access Tokens. Auditors must inspect recent action runs and release logs during the exposure window.
  • Cloud IAM Credentials: AWS, Azure, and GCP session tokens. CloudTrail and Activity Logs should be queried for AssumeRole or write operations originating from unexpected IP addresses.
  • NPM and Package Registries: Publishing tokens and credentials. Registry profiles must be audited for unauthorized version publishes or token additions.

Timeline

4 of 4 rows

Timeline
DateEventDescriptionSource
Apr 22, 2026First seenFirst seen recorded for Xinference PyPI 2.6.x Import-Time Credential Exfiltration.research.jfrog.com
Apr 22, 2026DiscoveryDiscovery recorded for Xinference PyPI 2.6.x Import-Time Credential Exfiltration.research.jfrog.com
Apr 22, 2026DisclosureDisclosure recorded for Xinference PyPI 2.6.x Import-Time Credential Exfiltration.research.jfrog.com
Apr 22, 2026Xinference PyPI 2.6.x Import-Time Credential ExfiltrationUnknownresearch.jfrog.com

Affected Software

0 of 0 rows

Affected Software
PackageEcosystemVersion RangeStatusConfidenceSource
No rows match the active filters.

IOC Clipboard

5 IOCs
hash077d49fa708f498969d7cdffe701eb64675baaa4968ded9bd97a4936dd56c21c
hashfe17e2ea4012d07d90ecb7793c1b0593a6138d25a9393192263e751660ec3cd0
domainwhereisitat.lucyatemysuperbox.space
hashe1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127
urlhttps://whereisitat.lucyatemysuperbox.space/

Tested Hunting Scripts

1 of 1 rows

Tested Hunting Scripts
TitleLanguageDescriptionRepositorySource
local repository and exported telemetry scopePythonDoes the telemetry scope contain patterns associated with Xinference PyPI 2.6.x Import-Time Credential Exfiltration?scripts/local_repository_and_exported_telemetry_scope.py opens in a new tabresearch.jfrog.com

Hunt Manifest: local repository and exported telemetry scope

Title
local repository and exported telemetry scope
Question
Does the telemetry scope contain patterns associated with Xinference PyPI 2.6.x Import-Time Credential Exfiltration?
Telemetry Family
Python
Repository
scripts/local_repository_and_exported_telemetry_scope.py
Show tested hunting scriptscripts/local_repository_and_exported_telemetry_scope.py
scripts/local_repository_and_exported_telemetry_scope.py opens in a new tabPython
#!/usr/bin/env python3
import os
import sys
import subprocess
from pathlib import Path

ROOT = sys.argv[1] if len(sys.argv) > 1 else "."
LOG_ROOT = os.environ.get("LOG_ROOT", "")
OUT = Path(os.environ.get("OUT", "hp-xinference-pypi-credential-hijack-scope"))

DOMAINS = ["whereisitat.lucyatemysuperbox.space"]
URLS = ["https://whereisitat.lucyatemysuperbox.space/"]
HASHES = ["e1e007ce4eab7774785617179d1c01a9381ae83abfd431aae8dba6f82d3ac127","077d49fa708f498969d7cdffe701eb64675baaa4968ded9bd97a4936dd56c21c","fe17e2ea4012d07d90ecb7793c1b0593a6138d25a9393192263e751660ec3cd0"]

# Collect unique indicators
indicators = set()
for group in [DOMAINS, URLS, HASHES]:
    for val in group:
        if val:
            indicators.add(val)

            indicators.add(val)

with open(indicators_file, "w") as f:
    for ind in sorted(indicators):
        f.write(ind + "\n")

print(f"[+] Written unique selectors to {indicators_file}")

# Walk local directory
print(f"[+] Scanning directory: {ROOT} for selectors...")
matches = []
exclude_dirs = {"node_modules", "vendor", "dist", ".git"}
for root, dirs, filenames in os.walk(ROOT):
    dirs[:] = [d for d in dirs if d not in exclude_dirs]
    for filename in filenames:
        filepath = Path(root) / filename
        try:
            content = filepath.read_text(errors="ignore")
            for ind in indicators:
                if ind in content:
                    matches.append(f"{filepath}: found '{ind}'")
        except Exception:
            pass  # pass # return or raise not needed here  # pass # return or raise not needed here  # pass # return or raise not needed here

if matches:
    (OUT / "repository-indicator-matches.txt").write_text("\n".join(matches) + "\n")
    print(f"[!] Found {len(matches)} matches in codebase!")

# Optional Log Scanning
if LOG_ROOT and os.path.exists(LOG_ROOT):
    print(f"[+] Scanning telemetry log directory: {LOG_ROOT}...")
    log_matches = []
    for root, _, filenames in os.walk(LOG_ROOT):
        for filename in filenames:
            filepath = Path(root) / filename
            try:
                content = filepath.read_text(errors="ignore")
                for ind in indicators:
                    if ind in content:
                        log_matches.append(f"{filepath}: found '{ind}'")
            except Exception:
                pass  # pass # return or raise not needed here  # pass # return or raise not needed here  # pass # return or raise not needed here
    if log_matches:
        (OUT / "exported-telemetry-indicator-matches.txt").write_text("\n".join(log_matches) + "\n")
        print(f"[!] Found {len(log_matches)} matches in logs!")

    if "PACKAGES" in globals() and PACKAGES:
        registry_dir = OUT / "registry"
        registry_dir.mkdir(exist_ok=True)
        for package in PACKAGES:
            if not package: continue
            safe_name = package.replace("/", "__")
            print(f"[+] Querying pip index for {package}...")
            res = subprocess.run(["python3", "-m", "pip", "index", "versions", package], capture_output=True, text=True)
            if res.returncode == 0:
                (registry_dir / f"pypi-{safe_name}-versions.txt").write_text(res.stdout)
            subprocess.run(["python3", "-m", "pip", "download", "--no-deps", package, "-d", str(registry_dir)], capture_output=True)

print(f"[+] Wrote scope artifacts under {OUT}")

Provenance & Sources

2 of 2 rows

Provenance & Sources
SourceTypeReliabilityClaimsEvidence
research.jfrog.comSecurity Researcher95%1JFrog reported that the legitimate PyPI package xinference shipped malicious versions 2.6.0, 2.6.1, and 2.6.2 with import-time code in xinference/__init__.py. The payload collected host and secret material into love[.]tar[.]gz and posted it to whereisitat[.]lucyatemysuperbox[.]space with header X-QT-SR: 14.
pypi.orgSecurity Researcher95%1JFrog reported that the legitimate PyPI package xinference shipped malicious versions 2.6.0, 2.6.1, and 2.6.2 with import-time code in xinference/__init__.py. The payload collected host and secret material into love[.]tar[.]gz and posted it to whereisitat[.]lucyatemysuperbox[.]space with header X-QT-SR: 14.