<?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: Cody Pack</title>
    <description>The latest articles on DEV Community by Cody Pack (@cody_pack_1175f5b6566117c).</description>
    <link>https://dev.to/cody_pack_1175f5b6566117c</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%2F4183404%2F5e1f574e-8fa0-4e9b-8dd7-1707096468b5.png</url>
      <title>DEV Community: Cody Pack</title>
      <link>https://dev.to/cody_pack_1175f5b6566117c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cody_pack_1175f5b6566117c"/>
    <language>en</language>
    <item>
      <title>I Publish npm Packages With No Tokens Stored Anywhere — Here's the Setup</title>
      <dc:creator>Cody Pack</dc:creator>
      <pubDate>Sat, 17 Oct 2026 22:31:01 +0000</pubDate>
      <link>https://dev.to/cody_pack_1175f5b6566117c/i-publish-npm-packages-with-no-tokens-stored-anywhere-heres-the-setup-2ic9</link>
      <guid>https://dev.to/cody_pack_1175f5b6566117c/i-publish-npm-packages-with-no-tokens-stored-anywhere-heres-the-setup-2ic9</guid>
      <description>&lt;p&gt;Last week I shipped version 0.3.0 of &lt;a href="https://github.com/blueeyez425-art/solaudit" rel="noopener noreferrer"&gt;SolAudit&lt;/a&gt;, a static analyzer for Solana programs. The publish step involved zero secrets. No npm token in GitHub Actions secrets. No token on my laptop. No token anywhere. And anyone can cryptographically verify that the tarball on npm came from a specific commit in my repo, built by a specific workflow run.&lt;/p&gt;

&lt;p&gt;This is npm's &lt;strong&gt;trusted publishing&lt;/strong&gt; (OIDC) plus &lt;strong&gt;Sigstore provenance&lt;/strong&gt;, and it took me about 30 minutes to set up. This post is the full walkthrough, including the two gotchas that cost me a failed run each.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with npm tokens
&lt;/h2&gt;

&lt;p&gt;The classic way to publish from CI is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;npm token create&lt;/code&gt; on your machine&lt;/li&gt;
&lt;li&gt;Paste it into GitHub repo secrets as &lt;code&gt;NPM_TOKEN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reference it in a workflow&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That token is a long-lived credential with full publish rights to your package. If it leaks — a compromised dependency, a malicious Action, a rogue &lt;code&gt;postinstall&lt;/code&gt; script in your CI environment — someone else publishes &lt;em&gt;as you&lt;/em&gt;, and every &lt;code&gt;npm install your-package&lt;/code&gt; pulls their code.&lt;/p&gt;

&lt;p&gt;This isn't hypothetical. Token theft and malicious version bumps are how several real npm supply-chain incidents have worked. The ecosystem's answer is to eliminate the standing credential entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What trusted publishing actually does
&lt;/h2&gt;

&lt;p&gt;Instead of a stored token, the GitHub Actions runner proves its identity to npm &lt;em&gt;at publish time&lt;/em&gt; using OpenID Connect (OIDC):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your workflow runs. GitHub mints a short-lived OIDC token that says: "I am workflow &lt;code&gt;publish.yml&lt;/code&gt; in repo &lt;code&gt;you/your-package&lt;/code&gt;, running on ref &lt;code&gt;main&lt;/code&gt;."&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm publish&lt;/code&gt; exchanges that token with the registry.&lt;/li&gt;
&lt;li&gt;npm checks: does this package have a configured trust relationship matching that exact repo, workflow file, and (optionally) environment?&lt;/li&gt;
&lt;li&gt;If yes, npm issues a temporary, publish-scoped credential that expires almost immediately.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's nothing to steal because there's nothing stored. An attacker who compromises your CI mid-run gets a credential that's scoped to one publish and dead within minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What provenance adds on top
&lt;/h2&gt;

&lt;p&gt;Trusted publishing controls &lt;em&gt;who can publish&lt;/em&gt;. Provenance lets &lt;em&gt;everyone else verify what was published&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When you publish from a trusted-publishing workflow, npm automatically generates a &lt;strong&gt;Sigstore attestation&lt;/strong&gt;: a signed, publicly verifiable statement binding the package version to the source repository, the commit SHA, and the workflow run that built it. It shows up as the green "Provenance" badge on the package's npm page, and anyone can verify it locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm audit signatures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That command checks the Sigstore signature on every installed package against the public transparency log. If someone tampered with the tarball or published it from anywhere other than your declared workflow, verification fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup, step by step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Link the package on npm
&lt;/h3&gt;

&lt;p&gt;On npmjs.com, go to your package → &lt;strong&gt;Settings → Publishing access → Trusted publishing&lt;/strong&gt;. Add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository owner:&lt;/strong&gt; your GitHub username or org&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository name:&lt;/strong&gt; your repo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workflow filename:&lt;/strong&gt; the exact filename, e.g. &lt;code&gt;publish.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment name:&lt;/strong&gt; leave blank unless you use GitHub environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two things to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The workflow filename must match &lt;strong&gt;exactly&lt;/strong&gt;, including extension. &lt;code&gt;publish.yml&lt;/code&gt; ≠ &lt;code&gt;publish.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For a brand-new package that doesn't exist on npm yet, you do one initial manual publish first (&lt;code&gt;npm publish&lt;/code&gt; from your machine with 2FA), then configure trusted publishing for all future releases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. The workflow
&lt;/h3&gt;

&lt;p&gt;Here's the actual workflow SolAudit uses (&lt;code&gt;.github/workflows/publish.yml&lt;/code&gt;):&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to npm&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;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&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;id-token&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 npm trusted publishing (OIDC)&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publish&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="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/setup-node@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;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;
          &lt;span class="na"&gt;registry-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://registry.npmjs.org&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;oven-sh/setup-bun@v2&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 dependencies&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;bun install&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;Build self-contained CLI bundle&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;bun run build:cli&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;Ensure npm supports trusted publishing&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;npm install -g npm@latest&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;Publish solaudit to npm&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cli&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;npm publish&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;permissions: id-token: write&lt;/code&gt;&lt;/strong&gt; — without this, the runner can't mint the OIDC token and the exchange fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;NODE_AUTH_TOKEN&lt;/code&gt;, no secrets block at all.&lt;/strong&gt; The &lt;code&gt;registry-url&lt;/code&gt; on &lt;code&gt;setup-node&lt;/code&gt; is just for registry config, not auth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;npm install -g npm@latest&lt;/code&gt;&lt;/strong&gt; — this is the gotcha that cost me a run. Trusted publishing requires a recent npm CLI (11.5.1+). The runner image ships an older one. Upgrade in the workflow or the OIDC exchange silently falls back to looking for a token you don't have.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Release
&lt;/h3&gt;

&lt;p&gt;Bump the version, merge to &lt;code&gt;main&lt;/code&gt;, then trigger the workflow manually from the Actions tab (that's what &lt;code&gt;workflow_dispatch&lt;/code&gt; gives you — a big green "Run workflow" button). I keep publishing manual on purpose: merging code and shipping a public package are two different decisions, and I want a deliberate click between them.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Verify
&lt;/h3&gt;

&lt;p&gt;After the run goes green:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view solaudit@0.3.0
npm audit signatures   &lt;span class="c"&gt;# in any project that installs it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the package page on npmjs.com shows the provenance badge, linking to the public Sigstore transparency log entry with the source repo and commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;SolAudit 0.3.0 shipped this way this week. The full chain is inspectable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://github.com/blueeyez425-art/solaudit" rel="noopener noreferrer"&gt;commit&lt;/a&gt; that bumped the version&lt;/li&gt;
&lt;li&gt;The Actions run that published it&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.npmjs.com/package/solaudit" rel="noopener noreferrer"&gt;npm page&lt;/a&gt; with the provenance badge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I ever lose my laptop, get phished, or a dependency in my CI turns malicious, the blast radius for "publish as me" is: nothing. There is no credential to take.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm only, for now.&lt;/strong&gt; Trusted publishing exists on PyPI and RubyGems too, but each registry implements it separately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your workflow file name is part of the trust config.&lt;/strong&gt; Rename &lt;code&gt;publish.yml&lt;/code&gt; and publishing breaks until you update npm's side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It protects the publish step, not your code.&lt;/strong&gt; If a malicious dependency lands in your actual build, provenance will faithfully attest to compromised code. You still need lockfile hygiene and dependency review.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But as a 30-minute change that deletes an entire credential class from your threat model, it's the best security-per-minute trade I've made on this project.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;SolAudit is a free, open-source static analyzer for Anchor/Solana programs — 94% precision on its public benchmark, with documented limits. &lt;a href="https://github.com/blueeyez425-art/solaudit" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/solaudit" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>npm</category>
      <category>githubactions</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>PlainSight — a local-first security checkup tool I'd actually sell to small businesses</title>
      <dc:creator>Cody Pack</dc:creator>
      <pubDate>Thu, 15 Oct 2026 19:25:15 +0000</pubDate>
      <link>https://dev.to/cody_pack_1175f5b6566117c/plainsight-a-local-first-security-checkup-tool-id-actually-sell-to-small-businesses-1hpf</link>
      <guid>https://dev.to/cody_pack_1175f5b6566117c/plainsight-a-local-first-security-checkup-tool-id-actually-sell-to-small-businesses-1hpf</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PlainSight&lt;/strong&gt; is a command-line tool that runs a passive security checkup on a small business's website and produces a &lt;strong&gt;plain-English report written entirely by a local open-weight model&lt;/strong&gt;. No cloud APIs. No client data leaves the machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun plainsight.ts checkup example-business.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Who would pay for it? CPAs, law firms, dentists, contractors, realtors — the small businesses that handle sensitive client data all day and have no IT department. They can't afford a penetration test ($5k+), but they &lt;em&gt;can&lt;/em&gt; afford a one-page "here's what's wrong with your website, in English" report for $49–129. That's the side hustle: run the tool, deliver the report, offer a quarterly recheck.&lt;/p&gt;

&lt;p&gt;The tool checks the things that actually matter at that scale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TLS certificate&lt;/strong&gt; health and expiry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security headers&lt;/strong&gt; (CSP, HSTS, X-Frame-Options, and friends)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email spoofing protections&lt;/strong&gt; (SPF/DMARC) — the #1 way small businesses get impersonated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accidentally exposed files&lt;/strong&gt; (&lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;, config backups)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP→HTTPS redirects&lt;/strong&gt;, mixed content, cookie flags&lt;/li&gt;
&lt;li&gt;Whether a &lt;strong&gt;security.txt&lt;/strong&gt; exists so researchers can report problems responsibly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every check is passive — the same requests any browser makes. There's an explicit ethics section in the README: you only scan sites you own or have written permission to test.&lt;/p&gt;

&lt;p&gt;The scan produces structured findings, and then the interesting part happens: a &lt;strong&gt;local model writes the report&lt;/strong&gt;. Not a template — an actual readable document, prioritized into "Fix these first," "Worth fixing soon," and "Good to know," in language a dentist's office manager understands.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Real run against my own other project's demo site (more on that below):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhmwjumthjsjrepv6prj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhmwjumthjsjrepv6prj.png" alt="PlainSight terminal demo — scan, then a locally-written plain-English report" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full artifacts from that run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📄 &lt;a href="https://github.com/blueeyez425-art/plainsight/blob/main/examples/sample-report-before.md" rel="noopener noreferrer"&gt;Sample report (written locally by an open-weight model)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔍 &lt;a href="https://github.com/blueeyez425-art/plainsight/blob/main/examples/sample-findings-before.json" rel="noopener noreferrer"&gt;Raw findings JSON the report was generated from&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/blueeyez425-art" rel="noopener noreferrer"&gt;
        blueeyez425-art
      &lt;/a&gt; / &lt;a href="https://github.com/blueeyez425-art/plainsight" rel="noopener noreferrer"&gt;
        plainsight
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Local-first security checkup tool for small businesses — passive scan + local open-weight AI writes a plain-English report. No client data ever leaves the machine.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;PlainSight&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Local-first security checkups for small business websites.&lt;/strong&gt;
Passive checks in, plain-English report out — written by an open-weight model running entirely on your machine.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/blueeyez425-art/plainsight/examples/demo-screenshot.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fblueeyez425-art%2Fplainsight%2FHEAD%2Fexamples%2Fdemo-screenshot.png" alt="PlainSight demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;bun plainsight.ts checkup example.com&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scans&lt;/strong&gt; the domain passively — the same requests any visitor's browser makes: TLS certificate, HTTP security headers, HTTP→HTTPS redirect, mixed content, cookie flags, email authentication (SPF/DMARC), and a handful of commonly exposed sensitive files (&lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;, config backups).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hands the raw findings to a local open-weight model&lt;/strong&gt; (via &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt;) that writes a calm, jargon-free report a business owner can actually read: what each issue is, why it matters to &lt;em&gt;their business&lt;/em&gt;, and one concrete fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saves a Markdown report&lt;/strong&gt; you can send as-is or render to PDF with &lt;code&gt;pandoc&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why local AI matters here&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;A security report is a map of a client's weaknesses. Sending that through a closed third-party API is…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/blueeyez425-art/plainsight" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The whole thing is one TypeScript file (~250 lines) running on Bun, with zero npm dependencies. Deliberately boring: the scanner is deterministic code, the model only does the writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Two halves, each doing what it's good at:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The scanner is code, not AI.&lt;/strong&gt; All checks are plain TypeScript: fetch the page, inspect headers and TLS, probe a short list of well-known sensitive paths, query DNS TXT records for SPF/DMARC. Deterministic, auditable, no hallucination risk in the &lt;em&gt;findings&lt;/em&gt;. A security tool that invents vulnerabilities is worse than useless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The report writer is an open-weight model via &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;.&lt;/strong&gt; The scanner hands the model the structured findings JSON plus a prompt that demands plain English, calm tone, and no alarmism. Default model is &lt;code&gt;llama3.1:8b&lt;/code&gt;; I also ran it on &lt;code&gt;gemma3&lt;/code&gt; — any Ollama model works via one env var:&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;OLLAMA_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gemma3:1b bun plainsight.ts checkup example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model never sees anything except the findings list — no cookies, no page bodies, nothing sensitive beyond "this header is missing." The report ends with a footer stating exactly which model wrote it and that no data left the machine. Transparency is the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;This project &lt;em&gt;only works&lt;/em&gt; because the model is open and runs locally. Three reasons, in order of how much they'd kill the business:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Confidentiality is the whole job.&lt;/strong&gt; A security report is, by definition, a list of a client's weaknesses. If I generate that report by shipping the findings to a closed third-party API, I've just taken a small business's vulnerability inventory and handed it to infrastructure neither of us controls. As the person selling security, that's the one thing I can't do. A local open-weight model makes the ethically correct architecture also the easiest one to build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Marginal cost is zero, so the price point works.&lt;/strong&gt; At $49–129 per report, a per-token API bill is survivable but annoying — and it scales the wrong way. With a local model, the hundredth report costs exactly what the first one did: nothing. That changes what the business can be — free "first checkup" lead magnets, quarterly rechecks, batch runs across a whole book of clients, all without watching a meter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. No lock-in, no deprecation roulette.&lt;/strong&gt; A closed provider can change pricing, deprecate a model, or decide my use case violates a policy revision. When the model is a file on my machine, the tool I sell today still works in two years, and I can swap &lt;code&gt;llama3.1&lt;/code&gt; for &lt;code&gt;gemma3&lt;/code&gt; for whatever comes next by changing one environment variable. The open ecosystem — Ollama, the open weights themselves, Bun — is the supply chain, and none of it can be taken away.&lt;/p&gt;

&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;Me — and it caught real problems.&lt;/p&gt;

&lt;p&gt;I maintain another open-source project, &lt;a href="https://github.com/blueeyez425-art/solaudit" rel="noopener noreferrer"&gt;SolAudit&lt;/a&gt; (a security scanner for Solana programs, because apparently I only build one kind of thing), with a demo site at &lt;code&gt;solaudit-web.vercel.app&lt;/code&gt;. PlainSight's first real scan was against it, and the report flagged &lt;strong&gt;missing Content-Security-Policy, HSTS, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy headers&lt;/strong&gt; — on the demo site of a &lt;em&gt;security tool&lt;/em&gt;. Embarrassing? A little. Exactly the kind of finding a small business needs? Absolutely.&lt;/p&gt;

&lt;p&gt;I fixed the headers in &lt;code&gt;vercel.json&lt;/code&gt;, redeployed, and re-ran the checkup:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Critical&lt;/th&gt;
&lt;th&gt;High&lt;/th&gt;
&lt;th&gt;Medium&lt;/th&gt;
&lt;th&gt;Low&lt;/th&gt;
&lt;th&gt;Info&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Before&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;After&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The only remaining finding is "no security.txt file" — fair enough, that's next. The before/after artifacts are in the repo's &lt;a href="https://github.com/blueeyez425-art/plainsight/tree/main/examples" rel="noopener noreferrer"&gt;&lt;code&gt;examples/&lt;/code&gt;&lt;/a&gt; folder.&lt;/p&gt;

&lt;p&gt;Did they pay? I invoiced myself $0 and left a tip jar full of lessons. But it validated the core promise: the tool finds real, fixable issues and explains them in language you'd actually act on. The first &lt;em&gt;external&lt;/em&gt; user is the next step — the report format is the deliverable for a freelance checkup service I'm piloting with local small businesses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — Gemma 3 is a tested report-writer backend (&lt;code&gt;OLLAMA_MODEL=gemma3:1b&lt;/code&gt;, verified end-to-end against the sample scan — Gemma wrote a complete plain-English report from the findings JSON), alongside Llama as the default. Open weights all the way down.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built during the challenge window (October 14–15, 2026). Scanner: TypeScript + Bun, zero dependencies. Reports: open-weight models via Ollama. MIT licensed — if you want to run this side hustle in your own town, the repo is yours.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>security</category>
      <category>ai</category>
    </item>
    <item>
      <title>I built a free static analyzer for Solana programs — here's what it catches and how it's built</title>
      <dc:creator>Cody Pack</dc:creator>
      <pubDate>Wed, 14 Oct 2026 02:26:30 +0000</pubDate>
      <link>https://dev.to/cody_pack_1175f5b6566117c/i-built-a-free-static-analyzer-for-solana-programs-heres-what-it-catches-and-how-its-built-3n54</link>
      <guid>https://dev.to/cody_pack_1175f5b6566117c/i-built-a-free-static-analyzer-for-solana-programs-heres-what-it-catches-and-how-its-built-3n54</guid>
      <description>&lt;p&gt;Solana exploits keep hitting the same bug classes: missing signer checks, arbitrary cross-program invocations, unchecked account deserialization, integer overflow. These aren't exotic — they're the same patterns that have drained hundreds of millions of dollars from on-chain programs, and they're detectable with static analysis before code ever gets deployed.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;SolAudit&lt;/strong&gt;: a free, MIT-licensed static analyzer for Anchor/Solana Rust programs. 0.2.0 shipped this week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it in 10 seconds:&lt;/strong&gt; &lt;code&gt;npx solaudit ./your-program&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Point SolAudit at a directory of &lt;code&gt;.rs&lt;/code&gt; files and it applies 11 security rules, then gives you a report grouped by severity — no RPC calls, no wallet, no build step:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;Missing signer checks on token transfers/mints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;Arbitrary CPI (caller-controlled program IDs), unchecked deserialization, type cosplay, insecure manual account closure, missing bump canonicalization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;Integer overflow on balance math, insecure account init, missing rent-exemption checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LOW&lt;/td&gt;
&lt;td&gt;Missing owner checks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each finding includes the exact line and a concrete remediation hint. Exit code is &lt;code&gt;1&lt;/code&gt; on any CRITICAL/HIGH finding, so it drops straight into CI as a gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three ways to use it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CLI&lt;/strong&gt; — &lt;code&gt;npx solaudit ./program&lt;/code&gt;, or &lt;code&gt;bun add -g solaudit&lt;/code&gt;. Outputs human-readable, &lt;code&gt;--json&lt;/code&gt;, or &lt;code&gt;--sarif&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web app&lt;/strong&gt; — &lt;a href="https://solaudit-web.vercel.app/" rel="noopener noreferrer"&gt;solaudit-web.vercel.app&lt;/a&gt;. Paste a public GitHub repo URL or upload a single &lt;code&gt;.rs&lt;/code&gt; file. No install.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Action&lt;/strong&gt; — on the &lt;a href="https://github.com/marketplace/actions/solaudit-security-scanner" rel="noopener noreferrer"&gt;Marketplace&lt;/a&gt;. Ten lines of YAML and every push gets scanned, with findings uploaded to your repo's Security tab as code-scanning alerts:&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="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="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;blueeyez425-art/solaudit@main&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;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./programs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  On accuracy — honest numbers
&lt;/h2&gt;

&lt;p&gt;On the committed labeled benchmark suite, the engine scores &lt;strong&gt;93.8% precision, 100% recall, 96.8% F1&lt;/strong&gt; on rule-covered categories.&lt;/p&gt;

&lt;p&gt;Those numbers describe that suite, not general effectiveness. One known gap remains: &lt;strong&gt;duplicate mutable accounts&lt;/strong&gt;. I built a "distinctness" heuristic for it, it produced false positives on common legitimate patterns (e.g., a deposit instruction's user/vault token accounts of the same type), so I didn't ship it. A scanner that cries wolf gets uninstalled; I'd rather have a smaller rule set people trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supply chain: verify the build yourself
&lt;/h2&gt;

&lt;p&gt;A security tool that asks you to trust its binaries shouldn't exist. Every npm publish of SolAudit goes through GitHub Actions &lt;strong&gt;trusted publishing&lt;/strong&gt; with signed &lt;a href="https://www.npmjs.com/package/solaudit#provenance" rel="noopener noreferrer"&gt;Sigstore provenance&lt;/a&gt; — the package on npm is cryptographically bound to an exact commit and workflow run in the public repo. There's no "someone's laptop" in the loop. npm displays the provenance badge on the package page.&lt;/p&gt;

&lt;h2&gt;
  
  
  The dogfooding story
&lt;/h2&gt;

&lt;p&gt;The repo's own CI runs SolAudit against its intentionally vulnerable example program on every push. Setting that up immediately caught a real bug — in my own Action: when a consuming repo had a local workspace package named &lt;code&gt;solaudit&lt;/code&gt;, &lt;code&gt;npx&lt;/code&gt; would resolve the &lt;em&gt;local&lt;/em&gt; package instead of the pinned npm release, and the scan silently ran... nothing. The fix: install the pinned CLI into a temp dir and invoke it directly. Self-scanning found a distribution bug before any user did. That's the loop working as advertised.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Closing the duplicate-mutable-accounts gap with a smarter heuristic that survives the false-positive review&lt;/li&gt;
&lt;li&gt;More rules from post-mortems of real exploits&lt;/li&gt;
&lt;li&gt;Reentrancy-via-CPI-callback detection&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/blueeyez425-art/solaudit" rel="noopener noreferrer"&gt;https://github.com/blueeyez425-art/solaudit&lt;/a&gt; (⭐ if useful)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/solaudit" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/solaudit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; &lt;a href="https://github.com/marketplace/actions/solaudit-security-scanner" rel="noopener noreferrer"&gt;https://github.com/marketplace/actions/solaudit-security-scanner&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://solaudit-web.vercel.app/" rel="noopener noreferrer"&gt;https://solaudit-web.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback, false positives, and rule requests are all welcome as GitHub issues. SolAudit is free and will keep being built either way — development doesn't depend on tips. That said, if it saved you real time or caught a real bug, there's a tip link in the README, and it's genuinely appreciated.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built by an independent security researcher. SolAudit is a first-pass scanner, not an audit — it doesn't replace manual review for anything holding real funds.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>solana</category>
      <category>security</category>
      <category>rust</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
