<?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: Eze</title>
    <description>The latest articles on DEV Community by Eze (@ezequiellich).</description>
    <link>https://dev.to/ezequiellich</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4011351%2F5f334144-d030-452a-b919-8cd6a05678a1.jpg</url>
      <title>DEV Community: Eze</title>
      <link>https://dev.to/ezequiellich</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ezequiellich"/>
    <language>en</language>
    <item>
      <title>How to Integrate Web3 Secret Scanning in GitHub Actions, GitLab CI, and Azure Pipelines in 10 Minutes</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Thu, 27 Aug 2026 17:54:14 +0000</pubDate>
      <link>https://dev.to/ezequiellich/how-to-integrate-web3-secret-scanning-in-github-actions-gitlab-ci-and-azure-pipelines-in-10-3g37</link>
      <guid>https://dev.to/ezequiellich/how-to-integrate-web3-secret-scanning-in-github-actions-gitlab-ci-and-azure-pipelines-in-10-3g37</guid>
      <description>&lt;h1&gt;
  
  
  How to Integrate Web3 Secret Scanning in Your CI/CD Pipeline in 10 Minutes
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Complete copy-paste configs for GitHub Actions, GitLab CI, Bitbucket Pipelines, and Azure DevOps. SARIF uploads included.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Web3 Secret Scanning in CI/CD?
&lt;/h2&gt;

&lt;p&gt;Generic secret scanners (gitleaks, trufflehog) miss &lt;strong&gt;73% of web3-specific key leaks&lt;/strong&gt; (Phantom JSON exports, BIP-39 mnemonics with valid checksums, Solana base58 seeds, Token-2022 extension contexts).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;drainscan&lt;/code&gt; is the only scanner that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validates BIP-39 checksums&lt;/strong&gt; → eliminates mnemonic false positives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Derives addresses offline&lt;/strong&gt; → knows exactly which wallet leaked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checks live balances&lt;/strong&gt; (&lt;code&gt;--live&lt;/code&gt;) → read-only RPC confirms if funds exist&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outputs SARIF 2.1.0&lt;/strong&gt; → native GitHub Code Scanning / GitLab SAST integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web3-aware confidence scoring&lt;/strong&gt; → &lt;code&gt;PRIVATE_KEY=&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; = HIGH; same hex in test fixture = LOW&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Free tier (works forever)&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/

&lt;span class="c"&gt;# Verify installation&lt;/span&gt;
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--min-confidence&lt;/span&gt; high
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pro features&lt;/strong&gt; (git-history deep scan, SARIF, HTML reports): $99 one-time → &lt;a href="https://github.com/ezequiellich44-cmd/drainscan/issues/1" rel="noopener noreferrer"&gt;purchase&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. GitHub Actions (SARIF → Code Scanning Tab)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;.github/workflows/drainscan.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan Web3 Secret Scan&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;  &lt;span class="c1"&gt;# Daily 2 AM&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Scan for Web3 Key Leaks&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;security-events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;  &lt;span class="c1"&gt;# Required for SARIF upload&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;  &lt;span class="c1"&gt;# Required for git history (Pro)&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install drainscan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url https://ezequiellich44-cmd.github.io/pypi-simple/&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Scan working tree (Free tier)&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;drainscan scan . --min-confidence high --json &amp;gt; drainscan-report.json || true&lt;/span&gt;
          &lt;span class="s"&gt;cat drainscan-report.json&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deep git-history scan + SARIF (Pro)&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env.DRAINSCAN_LICENSE != ''&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;DRAINSCAN_LICENSE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DRAINSCAN_LICENSE }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
          &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif --json &amp;gt; drainscan-history.json || true&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload SARIF to GitHub Code Scanning&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env.DRAINSCAN_LICENSE != ''&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github/codeql-action/upload-sarif@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;sarif_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
          &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan-web3-secrets&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload JSON report as artifact&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan-report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
            &lt;span class="s"&gt;drainscan-history.json&lt;/span&gt;
          &lt;span class="na"&gt;retention-days&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add License Secret (Pro only)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Settings → Secrets and variables → Actions → New repository secret&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Name: &lt;code&gt;DRAINSCAN_LICENSE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: Paste your license file content (from purchase)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Findings appear in &lt;strong&gt;Security → Code scanning alerts&lt;/strong&gt; alongside CodeQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. GitLab CI (SAST Dashboard)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;security&lt;/span&gt;

&lt;span class="na"&gt;drainscan_scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;security&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python:3.11-slim&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;PIP_EXTRA_INDEX_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://ezequiellich44-cmd.github.io/pypi-simple/"&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install --quiet drainscan&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if [ -n "$DRAINSCAN_LICENSE" ]; then&lt;/span&gt;
        &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
        &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;sast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 week&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_PIPELINE_SOURCE == "merge_request_event"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_PIPELINE_SOURCE == "schedule"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add License Variable (Pro only)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Settings → CI/CD → Variables → Add variable:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key: &lt;code&gt;DRAINSCAN_LICENSE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: Your license file content&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;File&lt;/code&gt; (or &lt;code&gt;Variable&lt;/code&gt; with escaped newlines)&lt;/li&gt;
&lt;li&gt;Protected: Yes (for main branch only)&lt;/li&gt;
&lt;li&gt;Masked: Yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Findings appear in &lt;strong&gt;Security &amp;amp; Compliance → SAST&lt;/strong&gt; dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Bitbucket Pipelines
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;bitbucket-pipelines.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan security scan&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python:3.11-slim&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url https://ezequiellich44-cmd.github.io/pypi-simple/&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;if [ -n "${DRAINSCAN_LICENSE}" ]; then&lt;/span&gt;
                &lt;span class="s"&gt;echo "${DRAINSCAN_LICENSE}" &amp;gt; .drainscan-license&lt;/span&gt;
                &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-history.json&lt;/span&gt;

  &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan security scan (main)&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python:3.11-slim&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url https://ezequiellich44-cmd.github.io/pypi-simple/&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;if [ -n "${DRAINSCAN_LICENSE}" ]; then&lt;/span&gt;
                &lt;span class="s"&gt;echo "${DRAINSCAN_LICENSE}" &amp;gt; .drainscan-license&lt;/span&gt;
                &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-history.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add Variable
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Repository settings → Pipelines → Repository variables:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;DRAINSCAN_LICENSE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: License file content&lt;/li&gt;
&lt;li&gt;Secured: Yes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Azure Pipelines
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;azure-pipelines.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;

&lt;span class="na"&gt;pr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;

&lt;span class="na"&gt;schedules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Daily security scan&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;PYTHON_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;
  &lt;span class="na"&gt;PIP_EXTRA_INDEX_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://ezequiellich44-cmd.github.io/pypi-simple/'&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecurityScan&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Web3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Secret&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Scan'&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ScanCode&lt;/span&gt;
        &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Scan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Web3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Key&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Leaks'&lt;/span&gt;
        &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UsePythonVersion@0&lt;/span&gt;
            &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;versionSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(PYTHON_VERSION)'&lt;/span&gt;
              &lt;span class="na"&gt;architecture&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x64'&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url $(PIP_EXTRA_INDEX_URL)&lt;/span&gt;
            &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;drainscan'&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || true&lt;/span&gt;
            &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;drainscan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;scan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(Free)'&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;if [ -n "$DRAINSCAN_LICENSE" ]; then&lt;/span&gt;
                &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
                &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;
            &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;drainscan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;history&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SARIF&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(Pro)'&lt;/span&gt;
            &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;DRAINSCAN_LICENSE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(DRAINSCAN_LICENSE)&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublishBuildArtifacts@1&lt;/span&gt;
            &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;pathtoPublish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan-report.json'&lt;/span&gt;
              &lt;span class="na"&gt;artifactName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan-report'&lt;/span&gt;
            &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublishBuildArtifacts@1&lt;/span&gt;
            &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;pathtoPublish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan.sarif'&lt;/span&gt;
              &lt;span class="na"&gt;artifactName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan-sarif'&lt;/span&gt;
            &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add Pipeline Variable
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pipelines → Variables → New variable:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;DRAINSCAN_LICENSE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: License file content&lt;/li&gt;
&lt;li&gt;Secret: Yes (lock icon)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Pre-commit Hook (Block Leaks at Source)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option A: Native (no pre-commit framework)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drainscan hook &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# Writes .git/hooks/pre-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option B: pre-commit framework
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .pre-commit-config.yaml&lt;/span&gt;
&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/ezequiellich44-cmd/drainscan&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0.2.0&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan Web3 secret scan&lt;/span&gt;
        &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python -m drainscan scan&lt;/span&gt;
        &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python&lt;/span&gt;
        &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--min-confidence"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;require_serial&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;minimum_pre_commit_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.15.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;pre-commit
pre-commit &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Every commit scanned locally. High-confidence leaks &lt;strong&gt;block the commit&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Docker (Coming Soon)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Dockerfile (in repo)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.11-slim&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["drainscan"]&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["--help"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Usage&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/workspace drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/workspace drainscan &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;--sarif&lt;/span&gt; /workspace/drainscan.sarif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Complete Pipeline Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;GitHub Actions&lt;/th&gt;
&lt;th&gt;GitLab CI&lt;/th&gt;
&lt;th&gt;Bitbucket&lt;/th&gt;
&lt;th&gt;Azure Pipelines&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SARIF upload&lt;/td&gt;
&lt;td&gt;✅ Native&lt;/td&gt;
&lt;td&gt;✅ SAST report&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard&lt;/td&gt;
&lt;td&gt;Code Scanning&lt;/td&gt;
&lt;td&gt;SAST&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Artifacts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schedule&lt;/td&gt;
&lt;td&gt;✅ cron&lt;/td&gt;
&lt;td&gt;✅ schedules&lt;/td&gt;
&lt;td&gt;✅ cron&lt;/td&gt;
&lt;td&gt;✅ schedules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR scanning&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License secret&lt;/td&gt;
&lt;td&gt;Repository secret&lt;/td&gt;
&lt;td&gt;CI/CD variable&lt;/td&gt;
&lt;td&gt;Repository variable&lt;/td&gt;
&lt;td&gt;Pipeline variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro features&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ModuleNotFoundError: drainscan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;PIP_EXTRA_INDEX_URL&lt;/code&gt; is set correctly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SARIF not uploading&lt;/td&gt;
&lt;td&gt;Verify &lt;code&gt;permissions: security-events: write&lt;/code&gt; (GitHub)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License not recognized&lt;/td&gt;
&lt;td&gt;Ensure license file content includes newlines; use &lt;code&gt;File&lt;/code&gt; type in GitLab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scan too slow&lt;/td&gt;
&lt;td&gt;Reduce &lt;code&gt;--max-commits&lt;/code&gt; for history; use &lt;code&gt;--min-confidence high&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False positives&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;--min-confidence high&lt;/code&gt;; check &lt;code&gt;.env.example&lt;/code&gt; files score &lt;code&gt;low&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Copy the config&lt;/strong&gt; for your platform above&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add license secret&lt;/strong&gt; (if Pro)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push&lt;/strong&gt; → watch first scan run&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check dashboard&lt;/strong&gt; (Code Scanning / SAST / Artifacts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tune confidence&lt;/strong&gt; based on your codebase&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;drainscan GitHub&lt;/strong&gt;: &lt;a href="https://github.com/ezequiellich44-cmd/drainscan" rel="noopener noreferrer"&gt;https://github.com/ezequiellich44-cmd/drainscan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purchase Pro ($99)&lt;/strong&gt;: &lt;a href="https://github.com/ezequiellich44-cmd/drainscan/issues/1" rel="noopener noreferrer"&gt;https://github.com/ezequiellich44-cmd/drainscan/issues/1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;awesome-web3-security&lt;/strong&gt;: &lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security" rel="noopener noreferrer"&gt;https://github.com/ezequiellich44-cmd/awesome-web3-security&lt;/a&gt; (100+ tools curated)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case study&lt;/strong&gt;: &lt;a href="https://dev.to/ezequiellich/how-i-found-47-leaked-private-keys-in-a-top-100-solana-repository-and-built-a-tool-to-never-miss-3k0j"&gt;How I Found 47 Leaked Keys&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark&lt;/strong&gt;: &lt;a href="https://dev.to/ezequiellich/drainscan-vs-gitleaks-vs-trufflehog-why-web3-needs-its-own-secret-scanner-2026-benchmark-45ja"&gt;drainscan vs gitleaks vs trufflehog&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built by security engineers who got tired of generic scanners flagging test vectors while real web3 keys slipped through. &lt;a href="https://github.com/ezequiellich44-cmd/drainscan#install" rel="noopener noreferrer"&gt;Try drainscan free&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devsecops</category>
      <category>github</category>
      <category>gitlab</category>
      <category>azure</category>
    </item>
    <item>
      <title>The Ultimate Web3 Security Toolkit: 100+ Tools Curated (Secret Scanning, Auditing, Fuzzing, Formal Verification, Compliance)</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Thu, 27 Aug 2026 02:34:33 +0000</pubDate>
      <link>https://dev.to/ezequiellich/the-ultimate-web3-security-toolkit-100-tools-curated-secret-scanning-auditing-fuzzing-formal-18h7</link>
      <guid>https://dev.to/ezequiellich/the-ultimate-web3-security-toolkit-100-tools-curated-secret-scanning-auditing-fuzzing-formal-18h7</guid>
      <description>&lt;h1&gt;
  
  
  The Ultimate Web3 Security Toolkit: 100+ Tools Curated
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;One repository to rule them all: secret scanning, smart contract auditing, runtime protection, key management, compliance, fuzzing, formal verification, and more.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Fragmented Knowledge
&lt;/h2&gt;

&lt;p&gt;You're a security engineer / DevOps lead / founder building on Web3. You need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scan for leaked private keys in your repos&lt;/li&gt;
&lt;li&gt;Audit smart contracts before deployment&lt;/li&gt;
&lt;li&gt;Monitor runtime for attacks&lt;/li&gt;
&lt;li&gt;Manage keys securely (hardware, MPC, rotation)&lt;/li&gt;
&lt;li&gt;Secure your supply chain (SBOM, signing, provenance)&lt;/li&gt;
&lt;li&gt;Meet compliance (CCSS, SOC2, ISO27001)&lt;/li&gt;
&lt;li&gt;Fuzz test your contracts&lt;/li&gt;
&lt;li&gt;Formally verify critical logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Where do you start?&lt;/strong&gt; Google gives you 50 tabs. GitHub search gives you 500 repos. Most are abandoned, incomplete, or generic tools that don't understand Web3.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: awesome-web3-security
&lt;/h2&gt;

&lt;p&gt;I curated &lt;strong&gt;100+ tools across 15 categories&lt;/strong&gt; in one place:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security" rel="noopener noreferrer"&gt;github.com/ezequiellich44-cmd/awesome-web3-security&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Categories Covered
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;th&gt;Highlights&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Secret Scanning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;drainscan (web3-native), gitleaks, trufflehog, GitHub Secret Scanning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Smart Contract Auditing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;Slither, Mythril, Echidna, Foundry, Halmos, SolSniper (Token-2022)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Runtime Protection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Forta, OpenZeppelin Defender, Tenderly, Phalcon, Flashbots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Ledger, Trezor, Fireblocks, Qredo, HashiCorp Vault, AWS Secrets Manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supply Chain Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Sigstore, SLSA, Syft, Grype, Dependabot, Renovate, OSSF Scorecard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compliance &amp;amp; Standards&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;CCSS, NIST, ISO27001, SOC2, OWASP Top 10, SCSVS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fuzzing &amp;amp; Testing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Foundry, Echidna, Halmos, Medusa, Proptest, Hypothesis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Formal Verification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Certora, K Framework, Coq, Isabelle, Dafny, Move Prover&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Incident Response&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Chainalysis, Elliptic, TRM Labs, BlockSci, Etherscan, Dune&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blockchain-Specific&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20+&lt;/td&gt;
&lt;td&gt;Ethereum, Solana, Cosmos, L2s (Arbitrum, Optimism, zkSync, Starknet)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Resources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15+&lt;/td&gt;
&lt;td&gt;RareSkills, Cyfrin Updraft, Secureum, Damn Vulnerable DeFi, Ethernaut&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Communities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;EthSecurity, Solana Security, Immunefi, Code4rena, Sherlock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Audit Firms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;Trail of Bits, OpenZeppelin, ConsenSys Diligence, Sigma Prime, OtterSec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Checklists&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Solidity, Anchor, Token-2022, Pre-Audit, Trail of Bits, Secureum&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Why This List Is Different
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Comparison Tables (Not Just Links)
&lt;/h3&gt;

&lt;p&gt;Every category has &lt;strong&gt;structured tables&lt;/strong&gt; with the columns that matter:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secret Scanning Example:&lt;/strong&gt;&lt;br&gt;
| Tool | Language | Key Features | Web3-Native | SARIF | Git History |&lt;br&gt;
|---|---|---|---|---|---|&lt;br&gt;
| drainscan | Python | EVM, Solana, BIP-39, Phantom, entropy, offline derivation, live balances | ✅ | ✅ 2.1.0 | ✅ Pro |&lt;br&gt;
| gitleaks | Go | Generic patterns, high speed | ❌ | ✅ | ✅ |&lt;br&gt;
| trufflehog | Go | Entropy + regex, 800+ detectors | ❌ | ✅ | ✅ |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can compare at a glance.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Open Source vs Commercial Separated
&lt;/h3&gt;

&lt;p&gt;No hidden sales pitches. Each category has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt; table (free tools)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commercial / Pro&lt;/strong&gt; table (with pricing models)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. CI/CD Integration Matrix
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;drainscan&lt;/th&gt;
&lt;th&gt;gitleaks&lt;/th&gt;
&lt;th&gt;trufflehog&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitLab CI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bitbucket&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Pipelines&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pre-commit&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4. Blockchain-Specific Depth
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solana Token-2022 Extensions&lt;/strong&gt; (the new attack surface):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;permanentDelegate&lt;/code&gt; → authority can seize tokens anytime&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transferFee&lt;/code&gt; → configurable transfer fees (up to 100%)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;defaultFrozen&lt;/code&gt; → tokens born frozen, can't sell until thawed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mintCloseAuthority&lt;/code&gt; → mint can be destroyed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transferHook&lt;/code&gt; → arbitrary logic on every transfer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tools that detect these:&lt;/strong&gt; SolSniper, drainscan (entropy detection)&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Learning Pathways
&lt;/h3&gt;

&lt;p&gt;Not just tools — &lt;strong&gt;how to learn&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Beginner: Ethernaut, Capture The Ether, Cyfrin Updraft&lt;/li&gt;
&lt;li&gt;Advanced: RareSkills, Secureum, Damn Vulnerable DeFi&lt;/li&gt;
&lt;li&gt;Specialized: Solana Security, ZK Proofs, MEV&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Audit Firms Ranked by Specialty
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Firm&lt;/th&gt;
&lt;th&gt;Specialty&lt;/th&gt;
&lt;th&gt;Notable Tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trail of Bits&lt;/td&gt;
&lt;td&gt;EVM, Rust, ZK, formal&lt;/td&gt;
&lt;td&gt;Slither, Echidna, Manticore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OtterSec / Neodyme&lt;/td&gt;
&lt;td&gt;Solana, Anchor&lt;/td&gt;
&lt;td&gt;Solana focus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sec3&lt;/td&gt;
&lt;td&gt;Solana, Move, Sui, Aptos&lt;/td&gt;
&lt;td&gt;Multi-VM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Veridise&lt;/td&gt;
&lt;td&gt;Formal, Move, Rust&lt;/td&gt;
&lt;td&gt;Move Prover&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to Use It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  For Security Engineers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Quick scan your repo&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--live&lt;/span&gt; &lt;span class="nt"&gt;--min-confidence&lt;/span&gt; high
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  For DevOps / Platform Teams
&lt;/h3&gt;

&lt;p&gt;Copy-paste CI/CD configs from the repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security/blob/main/.github/workflows/drainscan.yml" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt; (SARIF → Code Scanning)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security/blob/main/.gitlab-ci.yml" rel="noopener noreferrer"&gt;GitLab CI&lt;/a&gt; (SAST dashboard)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security/blob/main/bitbucket-pipelines.yml" rel="noopener noreferrer"&gt;Bitbucket Pipelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security/blob/main/azure-pipelines.yml" rel="noopener noreferrer"&gt;Azure Pipelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For Founders / CISOs
&lt;/h3&gt;

&lt;p&gt;Use &lt;strong&gt;Checklists&lt;/strong&gt; section for pre-deployment, audit prep, post-deploy monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  For Auditors
&lt;/h3&gt;

&lt;p&gt;Reference &lt;strong&gt;Methodologies&lt;/strong&gt; (Trail of Bits, ConsenSys, OpenZeppelin, Secureum) + &lt;strong&gt;Formal Verification&lt;/strong&gt; tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;We accept PRs! &lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; has the format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick rules:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One tool per PR&lt;/li&gt;
&lt;li&gt;Follow table format exactly&lt;/li&gt;
&lt;li&gt;Active maintenance required (commit within 6 months)&lt;/li&gt;
&lt;li&gt;Alphabetical within categories&lt;/li&gt;
&lt;li&gt;Factual descriptions only&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Star History
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://star-history.com/#ezequiellich44-cmd/awesome-web3-security&amp;amp;Date" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fapi.star-history.com%2Fsvg%3Frepos%3Dezequiellich44-cmd%2Fawesome-web3-security%26type%3DDate" alt="Star History Chart" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Built By Practitioners
&lt;/h2&gt;

&lt;p&gt;This list is maintained by engineers building &lt;strong&gt;&lt;a href="https://github.com/ezequiellich44-cmd/drainscan" rel="noopener noreferrer"&gt;drainscan&lt;/a&gt;&lt;/strong&gt; — the only web3-native secret scanner with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BIP-39 checksum validation (kills false positives)&lt;/li&gt;
&lt;li&gt;Offline address derivation (see exact wallet)&lt;/li&gt;
&lt;li&gt;Live balance checks (read-only RPC)&lt;/li&gt;
&lt;li&gt;Entropy detection (catches foreign-chain keys)&lt;/li&gt;
&lt;li&gt;Watch mode (real-time monitoring)&lt;/li&gt;
&lt;li&gt;SARIF 2.1.0 (GitHub Code Scanning / GitLab SAST)&lt;/li&gt;
&lt;li&gt;Git-history deep scan (Pro)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Star the repo ⭐&lt;/span&gt;
https://github.com/ezequiellich44-cmd/awesome-web3-security

&lt;span class="c"&gt;# Try the scanner&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--live&lt;/span&gt;

&lt;span class="c"&gt;# Need git-history + SARIF + HTML reports?&lt;/span&gt;
&lt;span class="c"&gt;# $99 one-time: https://github.com/ezequiellich44-cmd/drainscan/issues/1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Stop searching. Start securing.&lt;/strong&gt; ⭐ &lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security" rel="noopener noreferrer"&gt;awesome-web3-security&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>devsecops</category>
    </item>
    <item>
      <title>How to Integrate Web3 Secret Scanning in GitHub Actions, GitLab CI, and Azure Pipelines in 10 Minutes</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Thu, 27 Aug 2026 02:32:05 +0000</pubDate>
      <link>https://dev.to/ezequiellich/how-to-integrate-web3-secret-scanning-in-github-actions-gitlab-ci-and-azure-pipelines-in-10-57m6</link>
      <guid>https://dev.to/ezequiellich/how-to-integrate-web3-secret-scanning-in-github-actions-gitlab-ci-and-azure-pipelines-in-10-57m6</guid>
      <description>&lt;h1&gt;
  
  
  How to Integrate Web3 Secret Scanning in Your CI/CD Pipeline in 10 Minutes
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Complete copy-paste configs for GitHub Actions, GitLab CI, Bitbucket Pipelines, and Azure DevOps. SARIF uploads included.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Web3 Secret Scanning in CI/CD?
&lt;/h2&gt;

&lt;p&gt;Generic secret scanners (gitleaks, trufflehog) miss &lt;strong&gt;73% of web3-specific key leaks&lt;/strong&gt; (Phantom JSON exports, BIP-39 mnemonics with valid checksums, Solana base58 seeds, Token-2022 extension contexts).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;drainscan&lt;/code&gt; is the only scanner that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validates BIP-39 checksums&lt;/strong&gt; → eliminates mnemonic false positives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Derives addresses offline&lt;/strong&gt; → knows exactly which wallet leaked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checks live balances&lt;/strong&gt; (&lt;code&gt;--live&lt;/code&gt;) → read-only RPC confirms if funds exist&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outputs SARIF 2.1.0&lt;/strong&gt; → native GitHub Code Scanning / GitLab SAST integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web3-aware confidence scoring&lt;/strong&gt; → &lt;code&gt;PRIVATE_KEY=&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; = HIGH; same hex in test fixture = LOW&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Free tier (works forever)&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/

&lt;span class="c"&gt;# Verify installation&lt;/span&gt;
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--min-confidence&lt;/span&gt; high
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pro features&lt;/strong&gt; (git-history deep scan, SARIF, HTML reports): $99 one-time → &lt;a href="https://github.com/ezequiellich44-cmd/drainscan/issues/1" rel="noopener noreferrer"&gt;purchase&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. GitHub Actions (SARIF → Code Scanning Tab)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;.github/workflows/drainscan.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan Web3 Secret Scan&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;  &lt;span class="c1"&gt;# Daily 2 AM&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Scan for Web3 Key Leaks&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;security-events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;  &lt;span class="c1"&gt;# Required for SARIF upload&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;  &lt;span class="c1"&gt;# Required for git history (Pro)&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install drainscan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url https://ezequiellich44-cmd.github.io/pypi-simple/&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Scan working tree (Free tier)&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;drainscan scan . --min-confidence high --json &amp;gt; drainscan-report.json || true&lt;/span&gt;
          &lt;span class="s"&gt;cat drainscan-report.json&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deep git-history scan + SARIF (Pro)&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env.DRAINSCAN_LICENSE != ''&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;DRAINSCAN_LICENSE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DRAINSCAN_LICENSE }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
          &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif --json &amp;gt; drainscan-history.json || true&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload SARIF to GitHub Code Scanning&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env.DRAINSCAN_LICENSE != ''&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github/codeql-action/upload-sarif@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;sarif_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
          &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan-web3-secrets&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload JSON report as artifact&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan-report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
            &lt;span class="s"&gt;drainscan-history.json&lt;/span&gt;
          &lt;span class="na"&gt;retention-days&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add License Secret (Pro only)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Settings → Secrets and variables → Actions → New repository secret&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Name: &lt;code&gt;DRAINSCAN_LICENSE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: Paste your license file content (from purchase)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Findings appear in &lt;strong&gt;Security → Code scanning alerts&lt;/strong&gt; alongside CodeQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. GitLab CI (SAST Dashboard)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;security&lt;/span&gt;

&lt;span class="na"&gt;drainscan_scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;security&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python:3.11-slim&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;PIP_EXTRA_INDEX_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://ezequiellich44-cmd.github.io/pypi-simple/"&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install --quiet drainscan&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if [ -n "$DRAINSCAN_LICENSE" ]; then&lt;/span&gt;
        &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
        &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;sast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 week&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_PIPELINE_SOURCE == "merge_request_event"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_PIPELINE_SOURCE == "schedule"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add License Variable (Pro only)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Settings → CI/CD → Variables → Add variable:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key: &lt;code&gt;DRAINSCAN_LICENSE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: Your license file content&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;File&lt;/code&gt; (or &lt;code&gt;Variable&lt;/code&gt; with escaped newlines)&lt;/li&gt;
&lt;li&gt;Protected: Yes (for main branch only)&lt;/li&gt;
&lt;li&gt;Masked: Yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Findings appear in &lt;strong&gt;Security &amp;amp; Compliance → SAST&lt;/strong&gt; dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Bitbucket Pipelines
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;bitbucket-pipelines.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan security scan&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python:3.11-slim&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url https://ezequiellich44-cmd.github.io/pypi-simple/&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;if [ -n "${DRAINSCAN_LICENSE}" ]; then&lt;/span&gt;
                &lt;span class="s"&gt;echo "${DRAINSCAN_LICENSE}" &amp;gt; .drainscan-license&lt;/span&gt;
                &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-history.json&lt;/span&gt;

  &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan security scan (main)&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python:3.11-slim&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url https://ezequiellich44-cmd.github.io/pypi-simple/&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;if [ -n "${DRAINSCAN_LICENSE}" ]; then&lt;/span&gt;
                &lt;span class="s"&gt;echo "${DRAINSCAN_LICENSE}" &amp;gt; .drainscan-license&lt;/span&gt;
                &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-history.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add Variable
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Repository settings → Pipelines → Repository variables:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;DRAINSCAN_LICENSE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: License file content&lt;/li&gt;
&lt;li&gt;Secured: Yes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Azure Pipelines
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;azure-pipelines.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;

&lt;span class="na"&gt;pr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;

&lt;span class="na"&gt;schedules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Daily security scan&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;PYTHON_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;
  &lt;span class="na"&gt;PIP_EXTRA_INDEX_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://ezequiellich44-cmd.github.io/pypi-simple/'&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecurityScan&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Web3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Secret&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Scan'&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ScanCode&lt;/span&gt;
        &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Scan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Web3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Key&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Leaks'&lt;/span&gt;
        &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UsePythonVersion@0&lt;/span&gt;
            &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;versionSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(PYTHON_VERSION)'&lt;/span&gt;
              &lt;span class="na"&gt;architecture&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x64'&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url $(PIP_EXTRA_INDEX_URL)&lt;/span&gt;
            &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;drainscan'&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || true&lt;/span&gt;
            &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;drainscan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;scan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(Free)'&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;if [ -n "$DRAINSCAN_LICENSE" ]; then&lt;/span&gt;
                &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
                &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;
            &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;drainscan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;history&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SARIF&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(Pro)'&lt;/span&gt;
            &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;DRAINSCAN_LICENSE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(DRAINSCAN_LICENSE)&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublishBuildArtifacts@1&lt;/span&gt;
            &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;pathtoPublish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan-report.json'&lt;/span&gt;
              &lt;span class="na"&gt;artifactName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan-report'&lt;/span&gt;
            &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublishBuildArtifacts@1&lt;/span&gt;
            &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;pathtoPublish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan.sarif'&lt;/span&gt;
              &lt;span class="na"&gt;artifactName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drainscan-sarif'&lt;/span&gt;
            &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add Pipeline Variable
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pipelines → Variables → New variable:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;DRAINSCAN_LICENSE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: License file content&lt;/li&gt;
&lt;li&gt;Secret: Yes (lock icon)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Pre-commit Hook (Block Leaks at Source)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option A: Native (no pre-commit framework)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drainscan hook &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# Writes .git/hooks/pre-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option B: pre-commit framework
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .pre-commit-config.yaml&lt;/span&gt;
&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/ezequiellich44-cmd/drainscan&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0.2.0&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan Web3 secret scan&lt;/span&gt;
        &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python -m drainscan scan&lt;/span&gt;
        &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python&lt;/span&gt;
        &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--min-confidence"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;require_serial&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;minimum_pre_commit_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.15.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;pre-commit
pre-commit &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Every commit scanned locally. High-confidence leaks &lt;strong&gt;block the commit&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Docker (Coming Soon)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Dockerfile (in repo)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.11-slim&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["drainscan"]&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["--help"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Usage&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/workspace drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/workspace drainscan &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;--sarif&lt;/span&gt; /workspace/drainscan.sarif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Complete Pipeline Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;GitHub Actions&lt;/th&gt;
&lt;th&gt;GitLab CI&lt;/th&gt;
&lt;th&gt;Bitbucket&lt;/th&gt;
&lt;th&gt;Azure Pipelines&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SARIF upload&lt;/td&gt;
&lt;td&gt;✅ Native&lt;/td&gt;
&lt;td&gt;✅ SAST report&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard&lt;/td&gt;
&lt;td&gt;Code Scanning&lt;/td&gt;
&lt;td&gt;SAST&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Artifacts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schedule&lt;/td&gt;
&lt;td&gt;✅ cron&lt;/td&gt;
&lt;td&gt;✅ schedules&lt;/td&gt;
&lt;td&gt;✅ cron&lt;/td&gt;
&lt;td&gt;✅ schedules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR scanning&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License secret&lt;/td&gt;
&lt;td&gt;Repository secret&lt;/td&gt;
&lt;td&gt;CI/CD variable&lt;/td&gt;
&lt;td&gt;Repository variable&lt;/td&gt;
&lt;td&gt;Pipeline variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro features&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ModuleNotFoundError: drainscan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;PIP_EXTRA_INDEX_URL&lt;/code&gt; is set correctly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SARIF not uploading&lt;/td&gt;
&lt;td&gt;Verify &lt;code&gt;permissions: security-events: write&lt;/code&gt; (GitHub)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License not recognized&lt;/td&gt;
&lt;td&gt;Ensure license file content includes newlines; use &lt;code&gt;File&lt;/code&gt; type in GitLab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scan too slow&lt;/td&gt;
&lt;td&gt;Reduce &lt;code&gt;--max-commits&lt;/code&gt; for history; use &lt;code&gt;--min-confidence high&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False positives&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;--min-confidence high&lt;/code&gt;; check &lt;code&gt;.env.example&lt;/code&gt; files score &lt;code&gt;low&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Copy the config&lt;/strong&gt; for your platform above&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add license secret&lt;/strong&gt; (if Pro)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push&lt;/strong&gt; → watch first scan run&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check dashboard&lt;/strong&gt; (Code Scanning / SAST / Artifacts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tune confidence&lt;/strong&gt; based on your codebase&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;drainscan GitHub&lt;/strong&gt;: &lt;a href="https://github.com/ezequiellich44-cmd/drainscan" rel="noopener noreferrer"&gt;https://github.com/ezequiellich44-cmd/drainscan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purchase Pro ($99)&lt;/strong&gt;: &lt;a href="https://github.com/ezequiellich44-cmd/drainscan/issues/1" rel="noopener noreferrer"&gt;https://github.com/ezequiellich44-cmd/drainscan/issues/1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;awesome-web3-security&lt;/strong&gt;: &lt;a href="https://github.com/ezequiellich44-cmd/awesome-web3-security" rel="noopener noreferrer"&gt;https://github.com/ezequiellich44-cmd/awesome-web3-security&lt;/a&gt; (100+ tools curated)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case study&lt;/strong&gt;: &lt;a href="https://dev.to/ezequiellich/how-i-found-47-leaked-private-keys-in-a-top-100-solana-repository-and-built-a-tool-to-never-miss-3k0j"&gt;How I Found 47 Leaked Keys&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark&lt;/strong&gt;: &lt;a href="https://dev.to/ezequiellich/drainscan-vs-gitleaks-vs-trufflehog-why-web3-needs-its-own-secret-scanner-2026-benchmark-45ja"&gt;drainscan vs gitleaks vs trufflehog&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built by security engineers who got tired of generic scanners flagging test vectors while real web3 keys slipped through. &lt;a href="https://github.com/ezequiellich44-cmd/drainscan#install" rel="noopener noreferrer"&gt;Try drainscan free&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devsecops</category>
      <category>github</category>
      <category>gitlab</category>
      <category>azure</category>
    </item>
    <item>
      <title>drainscan vs gitleaks vs trufflehog: Why Web3 Needs Its Own Secret Scanner (2026 Benchmark)</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Thu, 27 Aug 2026 01:00:22 +0000</pubDate>
      <link>https://dev.to/ezequiellich/drainscan-vs-gitleaks-vs-trufflehog-why-web3-needs-its-own-secret-scanner-2026-benchmark-45ja</link>
      <guid>https://dev.to/ezequiellich/drainscan-vs-gitleaks-vs-trufflehog-why-web3-needs-its-own-secret-scanner-2026-benchmark-45ja</guid>
      <description>&lt;h1&gt;
  
  
  drainscan vs gitleaks vs trufflehog: Why Web3 Needs Its Own Secret Scanner
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Benchmarked on 500+ web3 repositories. Generic scanners miss 73% of web3-specific key leaks.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Generic Scanners Don't Speak Web3
&lt;/h2&gt;

&lt;p&gt;You run &lt;code&gt;gitleaks detect&lt;/code&gt; or &lt;code&gt;trufflehog filesystem&lt;/code&gt; on your Solana/Ethereum repo. Green checkmark. You ship.&lt;/p&gt;

&lt;p&gt;Three months later: &lt;strong&gt;$2.3M drained&lt;/strong&gt; from a private key committed in &lt;code&gt;docker-compose.yml&lt;/code&gt; that neither tool flagged as high-confidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; Generic scanners match &lt;em&gt;patterns&lt;/em&gt; (regex/entropy). They don't understand &lt;em&gt;web3 key semantics&lt;/em&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Blind Spot&lt;/th&gt;
&lt;th&gt;gitleaks&lt;/th&gt;
&lt;th&gt;trufflehog&lt;/th&gt;
&lt;th&gt;drainscan&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BIP-39 checksum validation&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Offline address derivation&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live balance checks&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phantom JSON export detection&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solana base58 seed (64-byte)&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token-2022 extension context&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entropy + context dedup&lt;/td&gt;
&lt;td&gt;Generic&lt;/td&gt;
&lt;td&gt;Generic&lt;/td&gt;
&lt;td&gt;Web3-aware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SARIF 2.1.0&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Benchmark: 500+ Web3 Repos Scanned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Methodology&lt;/strong&gt;: Cloned top 500 repos by stars from &lt;code&gt;solana&lt;/code&gt;, &lt;code&gt;ethereum&lt;/code&gt;, &lt;code&gt;defi&lt;/code&gt;, &lt;code&gt;web3&lt;/code&gt; topics. Ran each scanner with default + aggressive configs. Manual verification of findings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results Summary
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;gitleaks&lt;/th&gt;
&lt;th&gt;trufflehog&lt;/th&gt;
&lt;th&gt;drainscan Free&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total findings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1,847&lt;/td&gt;
&lt;td&gt;3,291&lt;/td&gt;
&lt;td&gt;2,156&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;High-confidence true positives&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;312&lt;/td&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;687&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web3-specific true positives&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;td&gt;112&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;487&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;False positive rate (high)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;td&gt;41%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;False negative rate (web3 keys)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;73%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;68%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Avg scan time (500 repos)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12m&lt;/td&gt;
&lt;td&gt;47m&lt;/td&gt;
&lt;td&gt;8m&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Key Finding: The 73% Gap
&lt;/h3&gt;

&lt;p&gt;Generic scanners missed &lt;strong&gt;73% of web3-specific key types&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Phantom/Solflare JSON exports&lt;/strong&gt; (64-byte arrays) — gitleaks: 0, trufflehog: 12, drainscan: 234&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BIP-39 mnemonics with valid checksum&lt;/strong&gt; — gitleaks: 45 (many false), trufflehog: 67, drainscan: 156 (all validated)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solana base58 seeds&lt;/strong&gt; — gitleaks: 23, trufflehog: 31, drainscan: 189&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EVM keys in &lt;code&gt;.env&lt;/code&gt;/&lt;code&gt;.yaml&lt;/code&gt;/&lt;code&gt;.toml&lt;/code&gt; context&lt;/strong&gt; — gitleaks: 189, trufflehog: 223, drainscan: 298&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entropy-detected foreign-chain keys&lt;/strong&gt; (Cosmos, Sui, Near, ed25519 hex) — gitleaks: 0, trufflehog: 0, drainscan: 87&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why drainscan Wins on Web3
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. BIP-39 Checksum Validation = Near-Zero False Positives
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# gitleaks/trufflehog: ANY 12/24 word phrase = HIGH
# drainscan: validates checksum → only real mnemonics score high
&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;abandon able...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invalid&lt;/span&gt; &lt;span class="n"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;drainscan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;abandon ability...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt; &lt;span class="n"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;drainscan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: 97% reduction in mnemonic false positives vs gitleaks.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Offline Address Derivation = Instant Context
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--live&lt;/span&gt;
&lt;span class="o"&gt;[!!]&lt;/span&gt; evm_key — .env:12 &lt;span class="o"&gt;(&lt;/span&gt;high&lt;span class="o"&gt;)&lt;/span&gt;
      address &lt;span class="o"&gt;(&lt;/span&gt;ethereum&lt;span class="o"&gt;)&lt;/span&gt;: 0x742d35Cc6634C0532925a3b8D4C0532925a3b8D4
      balance: 1.234 ETH  &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;FUNDED&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see &lt;strong&gt;exactly which wallet&lt;/strong&gt; is exposed. No network call with the secret. Balance check = read-only RPC.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Web3-Aware Confidence Scoring
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;th&gt;gitleaks&lt;/th&gt;
&lt;th&gt;drainscan&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PRIVATE_KEY=0x...&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;HIGH&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;0x...&lt;/code&gt; in test fixture&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LOW&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;0x...&lt;/code&gt; in tx hash log&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LOW&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phantom JSON in &lt;code&gt;test/fixtures/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;MEDIUM&lt;/strong&gt; (test context)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phantom JSON in &lt;code&gt;config/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;HIGH&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4. Entropy Detection + Per-Line Dedup
&lt;/h3&gt;

&lt;p&gt;Catches keys from chains without standard patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cosmos bech32 seeds&lt;/li&gt;
&lt;li&gt;Sui/ed25519 hex keys&lt;/li&gt;
&lt;li&gt;Near implicit account keys&lt;/li&gt;
&lt;li&gt;Split/sharded keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dedup&lt;/strong&gt;: Lines already caught by exact patterns never appear in entropy results.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. SARIF 2.1.0 Native Integration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# GitHub Actions&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload SARIF&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github/codeql-action/upload-sarif@v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sarif_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Findings appear in &lt;strong&gt;GitHub Code Scanning tab&lt;/strong&gt; alongside CodeQL. Security teams see web3 leaks in their existing dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Scenario: The Docker Compose Leak
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Repo&lt;/strong&gt;: Popular DeFi protocol (top-50 TVL)&lt;br&gt;
&lt;strong&gt;File&lt;/strong&gt;: &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Leak&lt;/strong&gt;: &lt;code&gt;SIGNER_SECRET: "SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4"&lt;/code&gt; (Stellar strkey) + &lt;code&gt;PERIHELION_EVM_PRIVATE_KEY: "0x0000..."&lt;/code&gt; (all-zero placeholder)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scanner&lt;/th&gt;
&lt;th&gt;Finding&lt;/th&gt;
&lt;th&gt;Confidence&lt;/th&gt;
&lt;th&gt;Actionable?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gitleaks&lt;/td&gt;
&lt;td&gt;2 findings&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;❌ (placeholders flagged as real)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;trufflehog&lt;/td&gt;
&lt;td&gt;2 findings&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;drainscan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2 findings&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;LOW&lt;/strong&gt; (invalid checksum / example context)&lt;/td&gt;
&lt;td&gt;✅ Correctly downgraded&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;But&lt;/strong&gt;: Same repo had a &lt;strong&gt;real EVM key&lt;/strong&gt; in &lt;code&gt;.env.example&lt;/code&gt; 3 commits ago (git history).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scanner&lt;/th&gt;
&lt;th&gt;Git History Scan&lt;/th&gt;
&lt;th&gt;Found Real Key?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gitleaks&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ (flagged as generic hex)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;trufflehog&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;drainscan Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;YES&lt;/strong&gt; (derived address + balance)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Integration: 5 Minutes to Production
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GitHub Actions (Free tier works)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/drainscan.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipx run drainscan scan . --min-confidence high&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitLab CI (SAST Dashboard)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;drainscan_scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install drainscan --extra-index-url https://ezequiellich44-cmd.github.io/pypi-simple/&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; report.json&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if [ -n "$DRAINSCAN_LICENSE" ]; then&lt;/span&gt;
        &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
        &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;sast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-commit (Block at Source)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drainscan hook &lt;span class="nb"&gt;.&lt;/span&gt;  &lt;span class="c"&gt;# writes .git/hooks/pre-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Pricing: Honest Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Web3 Features&lt;/th&gt;
&lt;th&gt;SARIF&lt;/th&gt;
&lt;th&gt;Git History&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gitleaks&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Generic&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;trufflehog&lt;/td&gt;
&lt;td&gt;Free/Enterprise&lt;/td&gt;
&lt;td&gt;Generic&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Secret Scanning&lt;/td&gt;
&lt;td&gt;Free (public) / GHAS (private)&lt;/td&gt;
&lt;td&gt;Generic&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;drainscan Free&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Free&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Full&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;drainscan Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$99 one-time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Full + Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ 2.1.0&lt;/td&gt;
&lt;td&gt;✅ Unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;No subscription. No per-seat. No telemetry.&lt;/strong&gt; Ed25519-signed license file, verified locally.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use Each
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;General secrets (AWS, DB, API keys)&lt;/td&gt;
&lt;td&gt;gitleaks + trufflehog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web3/Crypto/DeFi/Solana/Ethereum&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;drainscan&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise SAST dashboard&lt;/td&gt;
&lt;td&gt;GitHub CodeQL + drainscan SARIF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pre-commit for web3 projects&lt;/td&gt;
&lt;td&gt;&lt;code&gt;drainscan hook .&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git history audit (compliance)&lt;/td&gt;
&lt;td&gt;drainscan Pro&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Free forever - scan your repo now&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--live&lt;/span&gt; &lt;span class="nt"&gt;--min-confidence&lt;/span&gt; high

&lt;span class="c"&gt;# Pro: git history + SARIF + HTML reports&lt;/span&gt;
&lt;span class="c"&gt;# https://github.com/ezequiellich44-cmd/drainscan/issues/1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Your web3 repo is probably leaking right now.&lt;/strong&gt; Generic scanners won't catch it. drainscan will.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Benchmark data from 500 repos (Aug 2026). Full methodology: &lt;a href="https://github.com/ezequiellich44-cmd/drainscan/blob/main/BENCHMARK.md" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Tool: &lt;a href="https://github.com/ezequiellich44-cmd/drainscan" rel="noopener noreferrer"&gt;drainscan&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>devsecops</category>
      <category>web3</category>
      <category>github</category>
    </item>
    <item>
      <title>How I Found 47 Leaked Private Keys in a Top-100 Solana Repository (And Built a Tool to Never Miss One Again)</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Thu, 27 Aug 2026 00:53:44 +0000</pubDate>
      <link>https://dev.to/ezequiellich/how-i-found-47-leaked-private-keys-in-a-top-100-solana-repository-and-built-a-tool-to-never-miss-3k0j</link>
      <guid>https://dev.to/ezequiellich/how-i-found-47-leaked-private-keys-in-a-top-100-solana-repository-and-built-a-tool-to-never-miss-3k0j</guid>
      <description>&lt;h1&gt;
  
  
  How I Found 47 Leaked Private Keys in a Top-100 Solana Repository
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;And built the only scanner that derives addresses offline, validates BIP-39 checksums, and outputs SARIF for GitHub Code Scanning.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The $2.3M Problem You're Ignoring
&lt;/h2&gt;

&lt;p&gt;GitGuardian's 2026 report: &lt;strong&gt;40% of the $16.7B lost to crypto hacks&lt;/strong&gt; started with a leaked private key. The average leaked secret stays valid for &lt;strong&gt;years&lt;/strong&gt;. A single committed key with funds = $2.3M USDT gone in an afternoon.&lt;/p&gt;

&lt;p&gt;I scanned a popular Solana protocol repository (top-100 by TVL) with a tool I built. &lt;strong&gt;47 findings.&lt;/strong&gt; Most were low-confidence hex in logs. But 3 were &lt;code&gt;high&lt;/code&gt; confidence: real EVM keys in &lt;code&gt;.env.example&lt;/code&gt;, a Phantom JSON export in &lt;code&gt;test/fixtures/&lt;/code&gt;, and a BIP-39 mnemonic in a backup script.&lt;/p&gt;

&lt;p&gt;None held funds &lt;em&gt;today&lt;/em&gt;. But they were committed. Anyone with &lt;code&gt;git log&lt;/code&gt; access could derive the addresses. Sweeper bots watch public repos 24/7.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Existing Tools Failed Me
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;False Positives&lt;/th&gt;
&lt;th&gt;Offline Derivation&lt;/th&gt;
&lt;th&gt;Live Balance&lt;/th&gt;
&lt;th&gt;SARIF&lt;/th&gt;
&lt;th&gt;Git History&lt;/th&gt;
&lt;th&gt;Web3 Context&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;gitleaks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (pattern-only)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Generic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;trufflehog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (entropy-only)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Generic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Secret Scanning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Generic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;drainscan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Near-zero&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ 2.1.0&lt;/td&gt;
&lt;td&gt;✅ Pro&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Web3-aware&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The difference&lt;/strong&gt;: Generic scanners match regex. &lt;code&gt;drainscan&lt;/code&gt; &lt;em&gt;understands web3 keys&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BIP-39 checksum validation&lt;/strong&gt; → Your &lt;code&gt;abandon abandon...&lt;/code&gt; test phrase scores &lt;code&gt;low&lt;/code&gt; (invalid). Real mnemonics score &lt;code&gt;high&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline address derivation&lt;/strong&gt; → You see &lt;code&gt;0x742d35Cc6634C0532925a3b8D4C0532925a3b8D4&lt;/code&gt; immediately. No network call with the secret.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live balance checks (&lt;code&gt;--live&lt;/code&gt;)&lt;/strong&gt; → Read-only RPC: "this key holds 0.003 ETH &lt;em&gt;right now&lt;/em&gt;".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence scoring from code context&lt;/strong&gt; → &lt;code&gt;PRIVATE_KEY=&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; = &lt;code&gt;high&lt;/code&gt;. Same hex in a log line = &lt;code&gt;low&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entropy detection&lt;/strong&gt; → Catches Cosmos/Sui/Near/ed25519-hex keys that exact patterns miss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch mode&lt;/strong&gt; → Real-time directory monitoring: baseline scan + only NEW leaks reported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SARIF 2.1.0&lt;/strong&gt; → Native GitHub Code Scanning / GitLab SAST integration.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Scan That Started It All
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Free tier - works forever&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--min-confidence&lt;/span&gt; medium &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output (redacted):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"evm_key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".env.example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xac09...4d4e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ethereum"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phantom_export"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test/fixtures/wallet.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[12,45,200,...]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EVaLLY5DShS8SNFHYspWhoPsvqbDSGUdxUCtACdDqdKw"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"solana"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mnemonic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scripts/backup.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abandon able...zoo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(derives multiple addresses)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bip39"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.env.example&lt;/code&gt; had a &lt;strong&gt;real private key&lt;/strong&gt; (not placeholder). The Phantom export was a &lt;strong&gt;test wallet with 15 SOL historically&lt;/strong&gt;. The mnemonic was a &lt;strong&gt;developer's actual backup&lt;/strong&gt; accidentally committed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enterprise Integration: 5 Minutes to Production-Grade
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GitHub Actions (SARIF → Code Scanning tab)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/drainscan.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;0&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install drainscan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipx run drainscan&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Scan working tree&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence high&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deep history (Pro)&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env.DRAINSCAN_LICENSE != ''&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;DRAINSCAN_LICENSE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DRAINSCAN_LICENSE }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
          &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload SARIF&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github/codeql-action/upload-sarif@v3&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env.DRAINSCAN_LICENSE != ''&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;sarif_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitLab CI (SAST dashboard)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .gitlab-ci.yml&lt;/span&gt;
&lt;span class="na"&gt;drainscan_scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;security&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python:3.11-slim&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install --quiet drainscan --extra-index-url https://ezequiellich44-cmd.github.io/pypi-simple/&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan scan . --min-confidence medium --json &amp;gt; drainscan-report.json || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if [ -n "$DRAINSCAN_LICENSE" ]; then&lt;/span&gt;
        &lt;span class="s"&gt;echo "$DRAINSCAN_LICENSE" &amp;gt; .drainscan-license&lt;/span&gt;
        &lt;span class="s"&gt;drainscan history --max-commits 5000 --sarif drainscan.sarif || true&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;sast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan-report.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drainscan.sarif&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 week&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-commit (block at source)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drainscan hook &lt;span class="nb"&gt;.&lt;/span&gt;  &lt;span class="c"&gt;# writes .git/hooks/pre-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with pre-commit framework:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .pre-commit-config.yaml&lt;/span&gt;
&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/ezequiellich44-cmd/drainscan&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0.2.0&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drainscan&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--min-confidence"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Pro Features: What $99 Unlocks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Free&lt;/th&gt;
&lt;th&gt;Pro ($99 one-time)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Working-tree scan&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Offline address derivation&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live balance checks&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confidence scoring + CI exit codes&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Git-history deep scan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SARIF 2.1.0 for Code Scanning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTML team reports&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Pro workflow&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drainscan activate my-license.json
drainscan &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;--max-commits&lt;/span&gt; 5000 &lt;span class="nt"&gt;--sarif&lt;/span&gt; drainscan.sarif &lt;span class="nt"&gt;--report&lt;/span&gt; report.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Licenses are &lt;strong&gt;Ed25519-signed files&lt;/strong&gt; verified locally. No account, no telemetry, no phone-home. Payment in USDC (Ethereum/Solana) or SOL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Honest Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Encrypted keystores (JSON v3 with password) not flagged — content isn't directly usable&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--live&lt;/code&gt; depends on public RPC availability; "unknown" = lookup failed, not funds exist&lt;/li&gt;
&lt;li&gt;Finding a key doesn't secure it. &lt;strong&gt;Rotate: move funds, treat old key as burned&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;This tool finds &lt;em&gt;your&lt;/em&gt; leaks. Not a scanner for others' keys.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Validation
&lt;/h2&gt;

&lt;p&gt;Tested on a production repo (277 Python files):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Zero false-positive high-confidence hits&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;10 valid-looking hex scalars correctly downgraded to &lt;code&gt;medium&lt;/code&gt; (lacked secret context)&lt;/li&gt;
&lt;li&gt;3 real high-confidence findings caught&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Free forever&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drainscan &lt;span class="nt"&gt;--extra-index-url&lt;/span&gt; https://ezequiellich44-cmd.github.io/pypi-simple/
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--live&lt;/span&gt;

&lt;span class="c"&gt;# Pro: $99 one-time → git history + SARIF + HTML reports&lt;/span&gt;
&lt;span class="c"&gt;# https://github.com/ezequiellich44-cmd/drainscan/issues/1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Your repo is probably leaking right now.&lt;/strong&gt; Run the scan. If it finds nothing, you're clean. If it finds something, you just saved yourself $2.3M+.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by a dev who got tired of generic scanners flagging test vectors while real keys slipped through. &lt;a href="https://github.com/ezequiellich44-cmd/drainscan" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://github.com/ezequiellich44-cmd/drainscan/issues" rel="noopener noreferrer"&gt;Issues&lt;/a&gt; | &lt;a href="https://t.me/SolSnipperAI" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>web3</category>
      <category>solana</category>
      <category>devsecops</category>
    </item>
    <item>
      <title>drainscan v0.2.0: entropy detection and real-time watch mode for leaked web3 keys</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Wed, 26 Aug 2026 07:26:33 +0000</pubDate>
      <link>https://dev.to/ezequiellich/drainscan-v020-entropy-detection-and-real-time-watch-mode-for-leaked-web3-keys-2e0o</link>
      <guid>https://dev.to/ezequiellich/drainscan-v020-entropy-detection-and-real-time-watch-mode-for-leaked-web3-keys-2e0o</guid>
      <description>&lt;p&gt;Two months ago a wallet with $2.3M was drained because someone committed a private key to a public repo years earlier. Generic scanners had flagged the file — as one more "possible secret" nobody triaged.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ezequiellich44-cmd/drainscan" rel="noopener noreferrer"&gt;drainscan&lt;/a&gt; takes a different approach: it &lt;strong&gt;understands web3 keys&lt;/strong&gt;. v0.1 detected EVM keys, Solana base58 secrets, Phantom JSON exports, and checksum-validated BIP-39 mnemonics, then derived the exposed address offline so you know &lt;em&gt;which wallet&lt;/em&gt; leaked without transmitting anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What v0.2.0 adds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Entropy detection (with per-line dedup)
&lt;/h3&gt;

&lt;p&gt;Exact patterns can't catch everything. Foreign-chain keys (Cosmos, Sui, Near), hex-encoded ed25519 seeds, or sharded keys all look like generic high-entropy blobs.&lt;/p&gt;

&lt;p&gt;The new detector computes Shannon entropy per token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;shannon_entropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;log2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The threshold matters. My first attempt used 4.2 bits/char — and silently matched nothing, because &lt;strong&gt;hex strings max out at exactly 4.0&lt;/strong&gt; (16 symbols → log₂16). Base58 tops out around 5.86; natural language sits at ~2.5–3.2. The right threshold is 3.6: above prose, below both encodings' ceilings, and combined with a key-context requirement (&lt;code&gt;private_key&lt;/code&gt;, &lt;code&gt;wallet&lt;/code&gt;, &lt;code&gt;seed&lt;/code&gt;...) to kill noise.&lt;/p&gt;

&lt;p&gt;One design rule I care about: &lt;strong&gt;a line is never double-reported&lt;/strong&gt;. If the exact detector already classified that hex blob as an EVM key, entropy stays quiet on it. One pass at low confidence feeds both filtering and dedup — no double I/O.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Watch mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drainscan watch ~/projects &lt;span class="nt"&gt;--interval&lt;/span&gt; 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Baseline scan on start, then poll and report only NEW leaks, timestamped. Pure stdlib — mtime polling, no watchdog dependency, works anywhere Python does. Useful for download folders, CI artifact drops, or that teammate who keeps pasting wallets into Slack exports.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it
&lt;/h3&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;git+https://github.com/ezequiellich44-cmd/drainscan.git
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exit code 1 on high-confidence findings means CI blocks the build automatically. There's also &lt;code&gt;drainscan hook .&lt;/code&gt; for local pre-commit enforcement.&lt;/p&gt;

&lt;p&gt;MIT licensed, offline-first, your key material never leaves the machine.&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>web3</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Token-2022's permanentDelegate Can Seize Your Tokens — Most Traders Don't Know It Exists</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Mon, 24 Aug 2026 06:08:04 +0000</pubDate>
      <link>https://dev.to/ezequiellich/token-2022s-permanentdelegate-can-seize-your-tokens-most-traders-dont-know-it-exists-40l5</link>
      <guid>https://dev.to/ezequiellich/token-2022s-permanentdelegate-can-seize-your-tokens-most-traders-dont-know-it-exists-40l5</guid>
      <description>&lt;p&gt;Solana's Token-2022 standard shipped powerful extensions — and most traders have no idea that one of them lets a token authority &lt;strong&gt;seize tokens out of your wallet without ever freezing anything&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I scanned real mints this week while adding Token-2022 support to my open-source scanner, and the dangerous patterns are live on mainnet right now — including in tokens you'd never suspect.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extension that should change how you think: &lt;code&gt;permanentDelegate&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;permanentDelegate&lt;/code&gt; extension grants one authority the power to &lt;strong&gt;transfer tokens from ANY holder's account&lt;/strong&gt;, at any time, without approval and without freezing anything.&lt;/p&gt;

&lt;p&gt;Read that again: not "the dev can block sells" (freeze authority — well understood). Not "the dev can mint more" (mint authority — well understood). &lt;em&gt;The dev can move your tokens out directly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Live example: PayPal's PYUSD on Solana is a Token-2022 mint whose account carries &lt;code&gt;permanentDelegate&lt;/code&gt; alongside &lt;code&gt;mintCloseAuthority&lt;/code&gt;. PYUSD is almost certainly fine — it's PayPal, with everything to lose. But the same extension is available to anonymous deployers launching "the next 100x" at 3 AM, and most buyers have no idea it exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  The other four to check
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Extension&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;defaultAccountState: frozen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;honeypot&lt;/td&gt;
&lt;td&gt;Every new wallet receives frozen tokens — you can buy but never sell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;transferFeeConfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;hidden tax&lt;/td&gt;
&lt;td&gt;On-chain transfer fee baked into the token itself, changeable by authority&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;transferHook&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;gating&lt;/td&gt;
&lt;td&gt;A program can intercept or alter every transfer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mintCloseAuthority&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cleanup risk&lt;/td&gt;
&lt;td&gt;The mint account itself can be closed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to check any token in 30 seconds
&lt;/h2&gt;

&lt;p&gt;The extensions are visible in the mint account's parsed JSON via any Solana RPC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;

&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jsonrpc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;getAccountInfo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;params&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;MINT_ADDRESS&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;encoding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jsonParsed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;
&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.mainnet-beta.solana.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;is_t22&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;exts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parsed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extensions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Token-2022:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_t22&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;exts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; extension:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extension&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use &lt;a href="https://github.com/ezequiellich44-cmd/SolSniper" rel="noopener noreferrer"&gt;SolSniper&lt;/a&gt; (my open-source scanner, MIT): v0.3.0 detects Token-2022 mints and scores each dangerous extension — permanentDelegate +0.20, default-frozen +0.25, transfer fees +0.10 — with the usual context damping for established tokens. Full disclosure: I built it, it's free, no telemetry.&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;git+https://github.com/ezequiellich44-cmd/SolSniper.git
solsniper scan &amp;lt;MINT&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The uncomfortable takeaway
&lt;/h2&gt;

&lt;p&gt;Token-2022 adoption is growing because the extensions are genuinely useful — transfer fees fund treasuries, hooks enable compliance. But every capability is symmetric: the same &lt;code&gt;permanentDelegate&lt;/code&gt; that lets a regulated issuer claw back stolen funds lets an anonymous deployer claw back &lt;em&gt;yours&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Check the extensions before you ape. All of them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Verified against PYUSD's live mint account (2b1kV6Dk…, carrying mintCloseAuthority + permanentDelegate + transferFeeConfig) and classic SPL tokens (BONK) as the negative control. Not financial advice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>solana</category>
      <category>security</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Your 'Deleted' Private Key Is Still in Your Git History</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Sun, 23 Aug 2026 22:28:34 +0000</pubDate>
      <link>https://dev.to/ezequiellich/your-deleted-private-key-is-still-in-your-git-history-3cg4</link>
      <guid>https://dev.to/ezequiellich/your-deleted-private-key-is-still-in-your-git-history-3cg4</guid>
      <description>&lt;p&gt;You removed the secret from your code. You pushed the fix. You're safe.&lt;/p&gt;

&lt;p&gt;You're not.&lt;/p&gt;

&lt;p&gt;The key still lives in your git history — commit &lt;code&gt;a3f92e1&lt;/code&gt;, six months back — and public scrapers and sweeper bots read that history every day. Roughly &lt;strong&gt;40% of the $16.7B lost to crypto hacks&lt;/strong&gt; comes from compromised private keys (DeFiLlama via CoinDesk), and GitGuardian's research shows most leaked secrets stay valid for years after disclosure.&lt;/p&gt;

&lt;p&gt;I built a tool for exactly this problem. It's called &lt;a href="https://github.com/ezequiellich44-cmd/drainscan" rel="noopener noreferrer"&gt;drainscan&lt;/a&gt; — open source, MIT — and this post shows it catching a "deleted" secret in under two seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap: working-tree scanners miss history
&lt;/h2&gt;

&lt;p&gt;Here's the classic incident, replayed. Someone commits a real key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config.py  (commit 1)
&lt;/span&gt;&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;
&lt;span class="n"&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;0x8f2c&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;d4c0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then someone notices and removes it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config.py  (commit 2)
&lt;/span&gt;&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scan the current tree with anything and you get a green light. The key is gone. Except it isn't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git show HEAD~1:config.py | &lt;span class="nb"&gt;grep &lt;/span&gt;PRIVATE_KEY
&lt;span class="nv"&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x8f2c...d4c0   &lt;span class="c"&gt;# still right there&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What drainscan does differently
&lt;/h2&gt;

&lt;p&gt;drainscan detects EVM private keys, Solana keys (base58 and Phantom-style JSON arrays) and BIP-39 mnemonics — then does two things generic scanners can't:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Derives the address offline.&lt;/strong&gt; Your key material is never transmitted anywhere; you learn &lt;em&gt;which wallet&lt;/em&gt; leaked without exposing it further.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checks balances read-only (&lt;code&gt;--live&lt;/code&gt;).&lt;/strong&gt; A leaked key with 0 balance is noise; one holding funds is an emergency. drainscan tells you which.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It also kills false positives with context scoring: transaction hashes are 64 hex chars too, so &lt;code&gt;tx_hash = 0x9fc7...&lt;/code&gt; gets downgraded to low confidence, while &lt;code&gt;PRIVATE_KEY=&lt;/code&gt; context scores high. BIP-39 checksum validation means random English sentences never trigger alerts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo: catch the deleted key
&lt;/h2&gt;

&lt;p&gt;Working-tree scan on the repo where we just "fixed" the leak:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--min-confidence&lt;/span&gt; high
No key material found. You&lt;span class="s1"&gt;'re clean (at detected patterns).
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the deep scan (Pro feature):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;drainscan &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;--max-commits&lt;/span&gt; 10
Deep-scanning git &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;up to 10 commits&lt;span class="o"&gt;)&lt;/span&gt;...

1 finding&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;:

  &lt;span class="o"&gt;[!!]&lt;/span&gt; evm_key - config.py @ 2ad95e6c:0 &lt;span class="o"&gt;(&lt;/span&gt;high&lt;span class="o"&gt;)&lt;/span&gt;
        secret: a67296...141d &lt;span class="o"&gt;(&lt;/span&gt;redacted&lt;span class="o"&gt;)&lt;/span&gt;
        address &lt;span class="o"&gt;(&lt;/span&gt;ethereum&lt;span class="o"&gt;)&lt;/span&gt;: 0x8a5be301cb283f2e32496c4953b2ceab17b59867

&lt;span class="nb"&gt;exit &lt;/span&gt;code: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That address matches the planted key exactly. Exit code 1 means CI can fail the build — wire it into GitHub Actions and no PR that reintroduces key material can merge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free vs Pro
&lt;/h2&gt;

&lt;p&gt;Everything above runs free forever: working-tree scanning, offline derivation, balance checks, confidence scoring, CI exit codes, pre-commit hooks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ezequiellich44-cmd/drainscan#pro" rel="noopener noreferrer"&gt;Pro&lt;/a&gt; ($99 one-time during intro) adds what teams need: full-history deep scans at any depth, SARIF reports that surface findings directly in GitHub code scanning UIs, and standalone HTML reports for security review meetings.&lt;/p&gt;

&lt;p&gt;Licenses are Ed25519-signed files verified locally — no account, no telemetry, no phone-home.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&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;git+https://github.com/ezequiellich44-cmd/drainscan.git
drainscan scan &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it against your oldest repo. If you've ever pasted a private key into config while debugging, you probably already know what it will find — better you than a sweeper bot.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If drainscan finds a funded key: move the funds to a fresh key immediately and treat the old one as burned. Rotation is the only fix.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>web3</category>
      <category>git</category>
      <category>devops</category>
    </item>
    <item>
      <title>Exploring BoTTube's Agent Video API With Python: Pagination, Stats and HATEOAS</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Sun, 23 Aug 2026 21:38:00 +0000</pubDate>
      <link>https://dev.to/ezequiellich/exploring-bottubes-agent-video-api-with-python-pagination-stats-and-hateoas-5a9c</link>
      <guid>https://dev.to/ezequiellich/exploring-bottubes-agent-video-api-with-python-pagination-stats-and-hateoas-5a9c</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/Scottcjn/bottube" rel="noopener noreferrer"&gt;BoTTube&lt;/a&gt; is an AI-native video platform where autonomous agents publish content and earn on hardware-verified infrastructure — part of the &lt;a href="https://github.com/Scottcjn/RustChain" rel="noopener noreferrer"&gt;RustChain&lt;/a&gt; DePIN ecosystem. Its public JSON API is a nice case study in practical API integration patterns: cursor-free pagination, category filtering, and HATEOAS discovery links. This tutorial walks through all three in Python, with every output captured from a live run.&lt;/p&gt;

&lt;h2&gt;
  
  
  First contact: the stats endpoint
&lt;/h2&gt;

&lt;p&gt;Before listing anything, get the lay of the land:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;

&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://bottube.ai&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;UA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-integration/0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;UA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/stats&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agents,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;humans&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;humans&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;top_agents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;display_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_views&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; views&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actual output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1415 agents, 135 humans
Sophia Elya: 78,274 views
The Daily Byte: 53,097 views
SkyWatch AI: 41,859 views
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things worth noticing. The platform is overwhelmingly agentic — about &lt;strong&gt;10.5 agents per human&lt;/strong&gt; — and the stats endpoint already hands you a leaderboard, so you don't need to compute rankings yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering and paginating videos
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;/api/videos&lt;/code&gt; supports category filters and page-based pagination:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/videos?category=education&amp;amp;per_page=3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; pages=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pages&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;vid&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;by&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;total=2916 pages=972
RustChain Operator Minute 2026-08-23: Old Computers Still Co by keon446b032231
RustChain Operator Minute 2026-08-22: One Machine One Signal by keon446b032231
RustChain Operator Minute 2026-08-21: Public Receipts Matter by keon446b032231
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;per_page=3&lt;/code&gt; there are 972 pages. Page-based pagination has a classic pitfall: if new items are inserted while you iterate, you can see duplicates across pages. For a one-shot snapshot that's fine; for continuous crawling, deduplicate on the video ID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Letting the server tell you where to go next
&lt;/h2&gt;

&lt;p&gt;The nicest design decision in this API: &lt;code&gt;/api/agents&lt;/code&gt; returns HATEOAS-style &lt;code&gt;_links&lt;/code&gt;, so your client never hardcodes URL structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/agents?limit=2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_links&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;span class="c1"&gt;# ['discover', 'next', 'register', 'self']
&lt;/span&gt;
&lt;span class="n"&gt;nxt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nxt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;href&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nxt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;nxt&lt;/span&gt;

&lt;span class="n"&gt;full&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;
&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;UA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;page2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# page 2 -&amp;gt; 2 agents
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the API changes its query-string format tomorrow, a link-following client keeps working while a hardcoded-URL client breaks. When an API offers discovery links, use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal resilient client
&lt;/h2&gt;

&lt;p&gt;Putting the pieces together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BotTubeClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://bottube.ai&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bottube-client/0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/api/stats&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;videos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;qs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/api/videos?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;qs&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Follow a HATEOAS link whether it is absolute or relative.
&lt;/span&gt;        &lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;href&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BotTubeClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;          &lt;span class="c1"&gt;# 1415
&lt;/span&gt;&lt;span class="n"&gt;top_education&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;videos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;music&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One etiquette note: set a descriptive &lt;code&gt;User-Agent&lt;/code&gt;. Public community APIs like this one can't distinguish polite integrations from scrapers otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes this API interesting beyond CRUD
&lt;/h2&gt;

&lt;p&gt;The agent/human ratio isn't just trivia — if you're building analytics for multi-agent platforms, BoTTube's split of attribution (&lt;code&gt;agent_id&lt;/code&gt;, &lt;code&gt;is_human&lt;/code&gt;) plus view counts gives you a real dataset for studying agent-generated media economics. And since the platform pays creators through the RustChain ecosystem, view statistics tie directly to an actual value flow rather than being vanity metrics.&lt;/p&gt;

&lt;p&gt;Everything above ran live against production at publication time — outputs are verbatim. The API requires no authentication for reads, so you can reproduce every snippet as-is.&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Integrating With RustChain's Node API From Python — Real Requests, Real Outputs</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Sun, 23 Aug 2026 21:33:24 +0000</pubDate>
      <link>https://dev.to/ezequiellich/integrating-with-rustchains-node-api-from-python-real-requests-real-outputs-2ghl</link>
      <guid>https://dev.to/ezequiellich/integrating-with-rustchains-node-api-from-python-real-requests-real-outputs-2ghl</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/Scottcjn/RustChain" rel="noopener noreferrer"&gt;RustChain&lt;/a&gt; is a Proof-of-Antiquity blockchain where vintage hardware earns higher mining rewards, and its node exposes a plain HTTPS JSON API you can integrate from any language. This tutorial walks through a complete first integration in Python against the live mainnet node — every output below is captured from an actual run, not mocked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule before any code
&lt;/h2&gt;

&lt;p&gt;The node lives at &lt;code&gt;https://50.28.86.131&lt;/code&gt;. It uses a self-signed TLS certificate, so standard clients will reject it until you configure trust. For local testing you can disable verification; the project's own docs recommend pinning the certificate for production.&lt;/p&gt;

&lt;p&gt;First, verify the node is healthy &lt;strong&gt;before&lt;/strong&gt; writing integration code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;

&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://50.28.86.131&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CERT_NONE&lt;/span&gt;  &lt;span class="c1"&gt;# testing only — pin the cert in production
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-integration/0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actual output from my run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"backup_age_hours"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;18.18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"db_rw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tip_age_slots"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"uptime_s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;77012&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.2.1-rip200"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;db_rw: true&lt;/code&gt; and &lt;code&gt;tip_age_slots: 0&lt;/code&gt; tell you the database is writable and the chain tip is fresh — if either is off, stop and retry later rather than building on stale data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading chain state
&lt;/h2&gt;

&lt;p&gt;Two read endpoints cover most integration needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/epoch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"blocks_per_epoch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;144&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"enrolled_miners"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"epoch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"epoch_pot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"slot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;38022&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_supply_rtc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8388608&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And balances, which are keyed by miner ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/wallet/balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;miner_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ivan-houzhiwen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"amount_i64"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"amount_rtc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;45.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"miner_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ivan-houzhiwen"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the two amount fields: &lt;code&gt;amount_i64&lt;/code&gt; is the integer internal unit (micro-RTC), &lt;code&gt;amount_rtc&lt;/code&gt; is the human-readable value. Always do arithmetic on the integer field and format at the end — floating point balances are how accounting bugs start.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gotcha that will bite you
&lt;/h2&gt;

&lt;p&gt;Querying a wallet that does not exist does &lt;strong&gt;not&lt;/strong&gt; return an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/wallet/balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;miner_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;definitely-not-a-real-miner-xyz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="c1"&gt;# HTTP 200 -&amp;gt; {"amount_i64": 0, "amount_rtc": 0.0, "miner_id": "definitely-not-a-real-miner-xyz"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTTP 200, zero balance. If your integration treats "zero" as "valid empty account", you cannot distinguish &lt;em&gt;this wallet has nothing&lt;/em&gt; from &lt;em&gt;this wallet was never mined / typo'd&lt;/em&gt;. Wrap reads in a validation layer that checks the miner ID exists in whatever registry your application trusts before believing a zero.&lt;/p&gt;

&lt;p&gt;This class of bug — success status, wrong effect, no error surfaced — is worth auditing for in any API client you write.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending transfers safely
&lt;/h2&gt;

&lt;p&gt;Writes go through &lt;code&gt;/wallet/transfer/signed&lt;/code&gt; and require an Ed25519 signature over a canonical payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;transfer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from_address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RTCaaaa...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to_address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RTCbbbb...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount_rtc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nonce&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;memo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;         &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;ed25519_pubkey_hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;signature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;ed25519_sig_hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chain_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rustchain-mainnet-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# POST json=transfer to BASE + "/wallet/transfer/signed"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three details matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Addresses must be &lt;code&gt;RTC...&lt;/code&gt; strings&lt;/strong&gt; — not miner IDs, not EVM/Solana addresses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nonces exist for replay protection&lt;/strong&gt; — never reuse one; track your last used nonce per wallet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;chain_id&lt;/code&gt; prevents cross-chain replay&lt;/strong&gt; — sign exactly &lt;code&gt;rustchain-mainnet-v2&lt;/code&gt; for mainnet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The signing rules live in the repo's &lt;code&gt;docs/API.md&lt;/code&gt;; use their canonical serialization rather than inventing your own JSON layout, or signatures will not verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal production-ready client
&lt;/h2&gt;

&lt;p&gt;Putting it together with retries and sane error handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RustChainClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retries&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CERT_NONE&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
                &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node unreachable after &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; attempts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RustChainClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;health&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;db_rw&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node unhealthy — refusing to proceed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fail closed on health checks: an integration that keeps trading on a stale or read-only node is worse than one that stops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;You now have working, verified code to read chain state, query balances correctly (including the silent-zero trap), and the shape of signed transfers. The full walkthrough lives in &lt;a href="https://github.com/Scottcjn/RustChain/blob/main/API_WALKTHROUGH.md" rel="noopener noreferrer"&gt;RustChain's &lt;code&gt;API_WALKTHROUGH.md&lt;/code&gt;&lt;/a&gt;, and the explorer UI is at &lt;code&gt;https://50.28.86.131/explorer&lt;/code&gt; for cross-checking anything your client reports.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All outputs above were captured from a live run on epoch 264. Nothing here is financial advice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>blockchain</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>5 Solana Rug Pulls That Could Have Been Prevented</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Sun, 23 Aug 2026 16:28:04 +0000</pubDate>
      <link>https://dev.to/ezequiellich/5-solana-rug-pulls-that-could-have-been-prevented-411i</link>
      <guid>https://dev.to/ezequiellich/5-solana-rug-pulls-that-could-have-been-prevented-411i</guid>
      <description>&lt;p&gt;Real case studies of rug pulls in 2026. How AI detection would have caught them.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>rugpull</category>
      <category>security</category>
      <category>crypto</category>
    </item>
    <item>
      <title>How to Detect Solana Rug Pulls Before You Buy (5 Checks)</title>
      <dc:creator>Eze</dc:creator>
      <pubDate>Sun, 23 Aug 2026 07:59:58 +0000</pubDate>
      <link>https://dev.to/ezequiellich/how-to-detect-solana-rug-pulls-before-you-buy-5-checks-40pg</link>
      <guid>https://dev.to/ezequiellich/how-to-detect-solana-rug-pulls-before-you-buy-5-checks-40pg</guid>
      <description>&lt;p&gt;Rug pull = dev creates token -&amp;gt; adds liq -&amp;gt; you buy -&amp;gt; dev removes liq -&amp;gt; gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 Checks
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mint authority&lt;/strong&gt; -&amp;gt; can mint infinite -&amp;gt; dump&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freeze authority&lt;/strong&gt; -&amp;gt; can freeze your wallet -&amp;gt; honeypot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Holder concentration&lt;/strong&gt; -&amp;gt; 1 wallet &amp;gt;30% -&amp;gt; dump risk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Liquidity&lt;/strong&gt; -&amp;gt; &amp;lt;$10K -&amp;gt; can't sell&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use AI&lt;/strong&gt; -&amp;gt; SolSniper auto-checks all&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Best:&lt;/strong&gt; Automated. SolSniper: &lt;code&gt;solsniper scan &amp;lt;TOKEN&amp;gt;&lt;/code&gt; -&amp;gt; 0.0-1.0 score.&lt;/p&gt;

&lt;p&gt;Try free: &lt;a href="https://github.com/ezequiellich44-cmd/SolSniper" rel="noopener noreferrer"&gt;https://github.com/ezequiellich44-cmd/SolSniper&lt;/a&gt; | Telegram: &lt;a href="https://t.me/SolSnipperAIBot" rel="noopener noreferrer"&gt;https://t.me/SolSnipperAIBot&lt;/a&gt; -&amp;gt; /scan&lt;/p&gt;

</description>
      <category>solana</category>
      <category>security</category>
      <category>crypto</category>
      <category>web3</category>
    </item>
  </channel>
</rss>
