<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: sebastian-kuebeck</title>
    <description>The latest articles on DEV Community by sebastian-kuebeck (@sebastiankuebeck).</description>
    <link>https://dev.to/sebastiankuebeck</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3918161%2Febbb918e-0db0-45e1-8729-b26a28031279.png</url>
      <title>DEV Community: sebastian-kuebeck</title>
      <link>https://dev.to/sebastiankuebeck</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sebastiankuebeck"/>
    <language>en</language>
    <item>
      <title>How I Built PipCanary: A Scanner for Malicious PyPI Packages</title>
      <dc:creator>sebastian-kuebeck</dc:creator>
      <pubDate>Thu, 07 May 2026 14:27:43 +0000</pubDate>
      <link>https://dev.to/sebastiankuebeck/how-i-built-pipcanary-a-scanner-for-malicious-pypi-packages-2bmi</link>
      <guid>https://dev.to/sebastiankuebeck/how-i-built-pipcanary-a-scanner-for-malicious-pypi-packages-2bmi</guid>
      <description>&lt;p&gt;When the LiteLLM incident hit the news in March 2026, the vulnerability of the Python ecosystem became personal. A threat actor had hijacked a popular project to exfiltrate SSH keys and AWS credentials. While the official advice was to "delay updates," I knew that wasn't enough.&lt;/p&gt;

&lt;p&gt;We needed a way to catch a package with its hand in the cookie jar before it reached production.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with "Cool-down" Phases
&lt;/h2&gt;

&lt;p&gt;PyPI suggested delaying updates to let the community find malware first. But this has two fatal flaws:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Vulnerability Gap: You can't patch known security holes if you're stuck in a mandatory cool-down.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Human Error: If you forget the safeguard just once in a single environment, it’s game over.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Strategy: A Virtual Blast Chamber
&lt;/h2&gt;

&lt;p&gt;I decided to build PipCanary. The goal was simple: install the package in a sandbox, monitor its behavior, and scream if it tries to touch something it shouldn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Sandbox (bubblewrap)
&lt;/h3&gt;

&lt;p&gt;I needed a lightweight container that could run inside an existing Docker CI/CD pipeline. I chose bubblewrap. It allows me to create a temporary environment with zero access to sensitive files or network protocols unless explicitly permitted.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Monitor (strace)
&lt;/h3&gt;

&lt;p&gt;To see what the package was doing during pip install, I used strace. It tracks every system call made by the process and its subprocesses. If a package tries to open() your ~/.ssh/id_rsa, PipCanary sees it instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The "Lazy" Malware Test
&lt;/h3&gt;

&lt;p&gt;I struggled to write a PoC that executed during installation until I realized I could just script a "load and initialize" step inside the sandbox. This mimics how modern malware (like the PyTorch Lightning incident) operates by triggering the payload as soon as the module is imported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Validation: The PyTorch Lightning Attack
&lt;/h2&gt;

&lt;p&gt;Shortly after I finished the PoC, the PyTorch Lightning incident broke. This was a sophisticated attack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Malware hidden in a directory within the .whl file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Obfuscated JavaScript payload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Python code would download the bun runtime to execute the JS secretly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Static scanners probably missed it. PipCanary on the other hand monitors system calls, it didn't matter how obfuscated the JS was. The moment the bun runtime tried to reach for credentials, the "Canary" would die, and the CI/CD pipeline would halt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;PipCanary proves that you don't need a massive security suite to protect your supply chain. By combining a sandbox with behavioral monitoring, we can catch even the most sophisticated, obfuscated attacks.&lt;/p&gt;

&lt;p&gt;It’s still in its infancy, but seeing it protect my clients' infrastructure against real-world hits has been incredibly rewarding.&lt;/p&gt;

&lt;p&gt;Check out the project here: PipCanary on PyPi and GitHub (&lt;a href="https://github.com/sebastian-kuebeck/pipcanary" rel="noopener noreferrer"&gt;https://github.com/sebastian-kuebeck/pipcanary&lt;/a&gt;) &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LiteLLM Incident: &lt;a href="https://snyk.io/de/blog/poisoned-security-scanner-backdooring-litellm/" rel="noopener noreferrer"&gt;https://snyk.io/de/blog/poisoned-security-scanner-backdooring-litellm/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LiteLLM supply-chain attacks guidance: &lt;a href="https://blog.pypi.org/posts/2026-04-02-incident-report-litellm-telnyx-supply-chain-attack/" rel="noopener noreferrer"&gt;https://blog.pypi.org/posts/2026-04-02-incident-report-litellm-telnyx-supply-chain-attack/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyTorch Lightning Incident: &lt;a href="https://thehackernews.com/2026/04/pytorch-lightning-compromised-in-pypi.html" rel="noopener noreferrer"&gt;https://thehackernews.com/2026/04/pytorch-lightning-compromised-in-pypi.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>devops</category>
      <category>security</category>
      <category>container</category>
    </item>
  </channel>
</rss>
