<?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>Forem: Halfblood Prince</title>
    <description>The latest articles on Forem by Halfblood Prince (@halfblood_prince_32a44256).</description>
    <link>https://forem.com/halfblood_prince_32a44256</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%2F3857808%2F81187836-6b6d-4ca5-97b2-7a34f8325c4f.png</url>
      <title>Forem: Halfblood Prince</title>
      <link>https://forem.com/halfblood_prince_32a44256</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/halfblood_prince_32a44256"/>
    <language>en</language>
    <item>
      <title>I Almost Installed a Malicious Python Package: So, I Built trustcheck</title>
      <dc:creator>Halfblood Prince</dc:creator>
      <pubDate>Wed, 15 Apr 2026 19:18:36 +0000</pubDate>
      <link>https://forem.com/halfblood_prince_32a44256/i-almost-installed-a-malicious-python-package-so-i-built-trustcheck-37kk</link>
      <guid>https://forem.com/halfblood_prince_32a44256/i-almost-installed-a-malicious-python-package-so-i-built-trustcheck-37kk</guid>
      <description>&lt;p&gt;A few months ago, I was doing something completely normal. I needed a small Python library. So, I did what every Python developer does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &amp;lt;package&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But before hitting enter I paused. Something felt off. The package name looked right... but also slightly wrong. And that moment made me realize something uncomfortable:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We trust PyPI packages far more than we should.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That realization led me to build &lt;code&gt;trustcheck&lt;/code&gt; --- a tool that helps developers verify the trustworthiness of PyPI packages before installing them.&lt;/p&gt;




&lt;h2&gt;
  
  
  The uncomfortable truth about &lt;code&gt;pip install&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Installing dependencies is the most normal thing in software&lt;br&gt;
development. But under the hood we are doing something pretty risky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;something-from-the-internet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In many cases we don't check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  who published the package&lt;/li&gt;
&lt;li&gt;  whether the artifact matches the source repo&lt;/li&gt;
&lt;li&gt;  whether the maintainer account was compromised&lt;/li&gt;
&lt;li&gt;  whether the package name is a typo&lt;/li&gt;
&lt;li&gt;  whether the release came from a trusted build system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And attackers know this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attack #1: The typo that steals your secrets
&lt;/h2&gt;

&lt;p&gt;One of the simplest attacks is &lt;strong&gt;typosquatting&lt;/strong&gt;. An attacker uploads a package with a name that looks almost identical to&lt;br&gt;
a popular one.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Real package&lt;/th&gt;
&lt;th&gt;Malicious typo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reqeusts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;urllib3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;urlib3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tensorflow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tensorlfow&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Developers type quickly. CI scripts copy‑paste dependencies. And suddenly a malicious package gets installed.&lt;/p&gt;

&lt;p&gt;Real malicious PyPI packages have been caught doing things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  exfiltrating AWS credentials&lt;/li&gt;
&lt;li&gt;  stealing SSH keys&lt;/li&gt;
&lt;li&gt;  sending environment variables to remote servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All triggered by a simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;reqeusts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Attack #2: Dependency confusion
&lt;/h2&gt;

&lt;p&gt;This one is even sneakier.&lt;/p&gt;

&lt;p&gt;Imagine a company has an internal package called:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;internal-utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;An attacker uploads a public PyPI package with the same name. Then they give it a higher version number. If a developer runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;internal-utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;pip might install the malicious public package instead of the internal&lt;br&gt;
one. This technique was used in large-scale research that successfully&lt;br&gt;
injected packages into major companies.&lt;/p&gt;


&lt;h2&gt;
  
  
  Attack #3: The compromised maintainer
&lt;/h2&gt;

&lt;p&gt;Sometimes the attack doesn't involve fake packages at all. Instead, the real maintainer account gets compromised. Then the attacker publishes a new version like:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package 2.4.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Everything looks legitimate. Same project. Same PyPI page.&lt;br&gt;
But the new release contains malicious code. This has happened multiple times across open-source ecosystems.&lt;/p&gt;


&lt;h2&gt;
  
  
  The problem: we rarely verify packages
&lt;/h2&gt;

&lt;p&gt;The ecosystem is built on trust. But trust without verification is fragile.&lt;/p&gt;

&lt;p&gt;Developers typically check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  GitHub stars&lt;/li&gt;
&lt;li&gt;  number of downloads&lt;/li&gt;
&lt;li&gt;  README quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But those signals do not guarantee that a specific release artifact is&lt;br&gt;
trustworthy. That's the gap &lt;code&gt;trustcheck&lt;/code&gt; tries to fill.&lt;/p&gt;


&lt;h2&gt;
  
  
  Introducing trustcheck
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;trustcheck&lt;/code&gt; is a Python CLI that evaluates the trust signals of PyPI&lt;br&gt;
releases before installation. Instead of blindly installing a package, you can inspect it first. It analyzes signals like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  PyPI release metadata&lt;/li&gt;
&lt;li&gt;  provenance information&lt;/li&gt;
&lt;li&gt;  Trusted Publisher hints&lt;/li&gt;
&lt;li&gt;  repository links&lt;/li&gt;
&lt;li&gt;  publisher consistency&lt;/li&gt;
&lt;li&gt;  vulnerability records&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Turn blind trust into evidence‑based trust.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;trustcheck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic usage
&lt;/h2&gt;

&lt;p&gt;Check the trust signals for a package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trustcheck inspect requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check a specific version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trustcheck inspect sampleproject &lt;span class="nt"&gt;--version&lt;/span&gt; 4.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check dependencies too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trustcheck inspect sampleproject &lt;span class="nt"&gt;--version&lt;/span&gt; 4.0.0 &lt;span class="nt"&gt;--with-deps&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or inspect the full dependency tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trustcheck inspect sampleproject &lt;span class="nt"&gt;--version&lt;/span&gt; 4.0.0 &lt;span class="nt"&gt;--with-transitive-deps&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Enforcing repository expectations
&lt;/h2&gt;

&lt;p&gt;You can also verify that a package actually comes from the repository&lt;br&gt;
you expect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trustcheck inspect sampleproject &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version&lt;/span&gt; 4.0.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expected-repo&lt;/span&gt; https://github.com/pypa/sampleproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If something doesn't match, &lt;code&gt;trustcheck&lt;/code&gt; flags it.&lt;/p&gt;

&lt;p&gt;This helps defend against:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  dependency confusion&lt;/li&gt;
&lt;li&gt;  publisher drift&lt;/li&gt;
&lt;li&gt;  repository mismatches&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  CI integration
&lt;/h2&gt;

&lt;p&gt;trustcheck can output JSON for automation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trustcheck inspect sampleproject &lt;span class="nt"&gt;--version&lt;/span&gt; 4.0.0 &lt;span class="nt"&gt;--format&lt;/span&gt; json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it easy to integrate into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  CI pipelines&lt;/li&gt;
&lt;li&gt;  dependency review bots&lt;/li&gt;
&lt;li&gt;  internal security tooling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A better dependency workflow
&lt;/h2&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install random-package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A safer workflow looks like:&lt;/p&gt;

&lt;p&gt;1️⃣ Inspect package trust with &lt;code&gt;trustcheck&lt;/code&gt;&lt;br&gt;
2️⃣ Install dependency&lt;br&gt;
3️⃣ Scan for vulnerabilities with &lt;code&gt;pip-audit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Small change. Much safer ecosystem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Modern applications depend on hundreds of packages. A single malicious dependency can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  leak secrets&lt;/li&gt;
&lt;li&gt;  compromise builds&lt;/li&gt;
&lt;li&gt;  inject backdoors&lt;/li&gt;
&lt;li&gt;  affect thousands of downstream users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Supply chain security is becoming one of the most important areas in&lt;br&gt;
software development. &lt;code&gt;trustcheck&lt;/code&gt; is a small step toward bringing those ideas into everyday Python workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Halfblood-Prince/trustcheck" rel="noopener noreferrer"&gt;https://github.com/Halfblood-Prince/trustcheck&lt;/a&gt;&lt;br&gt;
PyPI: &lt;a href="https://pypi.org/project/trustcheck/" rel="noopener noreferrer"&gt;https://pypi.org/project/trustcheck/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>opensource</category>
      <category>devtool</category>
    </item>
  </channel>
</rss>
