<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/rss/atom-styles.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>codewhisperer.dev</title>
  <subtitle>Litos is a modern blogging theme built on Astro.js, designed for developers. It supports multiple post layouts, photo displays, project displays, and more, providing an elegant user experience and powerful customization capabilities.</subtitle>
  <link href="https://codewhisperer.dev//atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://codewhisperer.dev/" rel="alternate" type="text/html"/>
  <updated>2026-04-02T15:37:16.471Z</updated>
  <language>en</language>
  <id>https://codewhisperer.dev//</id>
  <author>
    <name>Itay</name>
    <uri>https://codewhisperer.dev/</uri>
  </author>
  <generator uri="https://github.com/Dnzzk2/Litos" version="5.0">Astro Litos Theme</generator>
  <rights>Copyright © 2026 Itay</rights>
  
  <entry>
    <title>Package maturity gates: a simple defense against npm supply chain attacks</title>
    <link href="https://codewhisperer.dev//posts/package-maturity-gates" rel="alternate" type="text/html"/>
    <id>https://codewhisperer.dev//posts/package-maturity-gates</id>
    <updated>2026-04-02T00:00:00.000Z</updated>
    <published>2026-04-02T00:00:00.000Z</published>
    <author>
      <name>Itay</name>
    </author>
    <summary type="text">Many npm supply chain attacks are detected quickly. Delaying very fresh package versions can block a surprising amount of risk for a small cost.</summary>
    <content type="html"><![CDATA[
<h2>If a package was published 20 minutes ago, maybe your production system should not be the first one to try it.</h2>
<p>There are many different defense tactics against various javascript library attacks, but one that I think is underappreciated is the idea of a “package maturity gate.”</p>
<p>Modern JavaScript package managers already have features that can enforce exactly that kind of caution.</p>
<p><strong>TLDR:</strong> if you only want the practical part, jump to <em><a href="#who-supports-this-today">Who supports this today?</a></em></p>
<p>They can refuse to install packages that are too fresh.</p>
<p>Not known-malicious packages. Not suspicious packages. Just very new ones.</p>
<p>And that sounds almost too simple, but even forcing packages to age by 1-2 days can cut a lot of risk - <a href="#recent-incidents">7 recent npm supply chain incidents</a> were caught within hours or a day of the malicious publish.</p>
<p>Very simple rule: do not install dependency versions until they are at least some minimum age.</p>
<p>This does not make a package safe. It does not solve typosquatting, malicious maintainers, or bad code that sat around for months.</p>
<p>But it does help against one very specific and very common problem in the Node.js ecosystem:
an attacker compromises a maintainer account or steals a publish token, pushes a malicious version, and people install it before anyone notices.</p>
<p>And that “before anyone notices” window is often shorter than people think.</p>
<h2>Why this matters</h2>
<p>Most teams are not manually auditing every transitive dependency update.</p>
<p>They run <code>npm install</code>, <code>pnpm install</code>, or <code>bun install</code>, trust the registry, trust the lockfile update, and move on.</p>
<p>That is understandable. Nobody wants to spend their entire week thinking about package provenance.</p>
<p>But supply chain attacks keep showing the same shape:</p>
<ul>
<li>Maintainer gets phished or token gets stolen</li>
<li>Malicious version gets published</li>
<li>Security researchers or affected maintainers notice suspicious behavior</li>
<li>Public disclosure follows shortly after</li>
</ul>
<p>If your CI or workstation installs during that fresh publish window, you are just unlucky.</p>
<p>So the question is not “how do I make npm perfectly safe?”
The question is more practical:</p>
<p><strong>How do I stop being part of the first wave?</strong></p>
<h2>Who supports this today?</h2>



































<table><thead><tr><th>Tool</th><th>Native maturity gate?</th><th>Install-script controls</th><th>Bottom line</th></tr></thead><tbody><tr><td><strong>Bun</strong></td><td>Yes. <code>install.minimumReleaseAge</code> lets you reject versions newer than a configured age, with exclusions for trusted packages. <a href="https://bun.sh/docs/runtime/bunfig" rel="noopener noreferrer" target="_blank">Docs</a></td><td>Script controls exist separately, but the maturity gate is the headline feature here.</td><td>Good built-in protection against brand-new malicious publishes.</td></tr><tr><td><strong>pnpm</strong></td><td>Yes. <code>minimumReleaseAge</code> applies age filtering to direct and transitive dependencies. <a href="https://pnpm.io/settings" rel="noopener noreferrer" target="_blank">Docs</a></td><td>Strong controls: <code>pnpm approve-builds</code>, <code>allowBuilds</code>, and explicit package approval instead of blindly allowing scripts. <a href="https://pnpm.io/cli/approve-builds" rel="noopener noreferrer" target="_blank">Docs</a></td><td>Probably the strongest native package-manager posture here right now.</td></tr><tr><td><strong>Deno</strong></td><td>Yes. <code>minimumDependencyAge</code> is supported in config. <a href="https://deno.com/blog/v2.6" rel="noopener noreferrer" target="_blank">Deno 2.6</a></td><td>Deno does not run npm lifecycle scripts by default; scripts must be explicitly allowed. <a href="https://docs.deno.com/runtime/reference/cli/install/#--allow-scripts" rel="noopener noreferrer" target="_blank">Docs</a></td><td>Very good defaults, especially because script execution is opt-in.</td></tr><tr><td><strong>npm</strong></td><td>Not a true minimum-age setting, but <code>--before</code> can install package versions that existed on or before a chosen date. <a href="https://docs.npmjs.com/cli/v11/commands/npm-install#before" rel="noopener noreferrer" target="_blank">Docs</a></td><td><code>ignore-scripts</code> is an important mitigation if you do not trust dependency install hooks. <a href="https://docs.npmjs.com/cli/v11/using-npm/config#ignore-scripts" rel="noopener noreferrer" target="_blank">Docs</a></td><td>Better than nothing, but less ergonomic than a real minimum-age policy.</td></tr></tbody></table>
<p>If you are on Bun or pnpm, I think this is a “just enable it” kind of feature.</p>
<p>If you are on Deno, you already get a nicer default security posture than the usual Node.js toolchain, especially around install scripts.</p>
<p>If you are on npm, you can still reduce risk with date-based cutoffs, but it is less clean than having an actual minimum-age policy built into normal installs.</p>
<h2>Recent incidents</h2>
<p>Below is the nicer version of the pattern.</p>





















































<table><thead><tr><th>Incident</th><th>Attack started</th><th>Detected / disclosed</th><th>Approximate exposure window</th></tr></thead><tbody><tr><td><a href="https://socket.dev/blog/npm-phishing-campaign-leads-to-prettier-tooling-packages-compromise" rel="noopener noreferrer" target="_blank">Prettier tooling compromise</a> (<code>eslint-config-prettier</code>, <code>eslint-plugin-prettier</code>)</td><td>July 18, 2025</td><td>July 19, 2025</td><td>~1 day</td></tr><tr><td><a href="https://jfrog.com/blog/new-compromised-packages-in-largest-npm-attack-in-history/" rel="noopener noreferrer" target="_blank">Qix maintainer compromise</a> (<code>debug</code>, <code>chalk-template</code>, <code>color-convert</code>, <code>strip-ansi</code>, others)</td><td>September 8, 2025</td><td>September 8, 2025</td><td>same day</td></tr><tr><td><a href="https://nx.dev/blog/s1ngularity-postmortem" rel="noopener noreferrer" target="_blank">Nx compromise</a></td><td>August 26, 2025</td><td>August 27, 2025</td><td>~1 day</td></tr><tr><td><a href="https://www.wiz.io/blog/shai-hulud-npm-supply-chain-attack" rel="noopener noreferrer" target="_blank">Shai-Hulud, first wave</a></td><td>September 16, 2025</td><td>September 16, 2025</td><td>same day</td></tr><tr><td><a href="https://www.esentire.com/security-advisories/new-npm-supply-chain-attack-identified-second-wave-of-shai-hulud" rel="noopener noreferrer" target="_blank">Shai-Hulud, second wave</a></td><td>November 24, 2025</td><td>November 24, 2025</td><td>same day</td></tr><tr><td><a href="https://www.endorlabs.com/learn/canisterworm" rel="noopener noreferrer" target="_blank">CanisterWorm / TeamPCP npm worm</a></td><td>March 21, 2026</td><td>March 21, 2026</td><td>same day</td></tr><tr><td><a href="https://securitylabs.datadoghq.com/articles/axios-npm-supply-chain-compromise/" rel="noopener noreferrer" target="_blank">Axios maintainer-account compromise</a></td><td>March 31, 2026</td><td>March 31, 2026</td><td>hours (<code>00:21-03:29 UTC</code> according to Datadog)</td></tr></tbody></table>
<p>The exact numbers are not the interesting part.</p>
<p>The interesting part is that many of these bad publishes were not invisible for weeks. In several cases they were discovered the same day or the next day.</p>
<p>That means a boring delay of 24 hours, 72 hours, or 7 days would have blocked at least some of the blast radius.</p>
<p>Not all of it, but enough to matter.</p>
<h2>Package maturity gates</h2>
<p>This defense is refreshingly unsophisticated.</p>
<p>Instead of trying to perfectly classify which package is good or bad, you just say:
“fresh publishes are higher risk, so we will not consume them immediately.”</p>
<p>That is it.</p>
<p>This works especially well because most projects do <strong>not</strong> actually need the newest transitive dependency version five minutes after release.</p>
<p>People often act like delaying packages by a few days is unbearable friction. In reality, most teams would not notice unless they are actively chasing a hotfix or testing a brand new release on purpose.</p>
<p>So the trade is pretty good:</p>
<ul>
<li>Small delay for normal installs</li>
<li>Big reduction in exposure to brand-new compromised publishes</li>
<li>Very cheap to explain and enforce</li>
</ul>
<p>This is one of the rare defenses that feels asymmetric in your favor.</p>
<p>Attackers need a fresh publish to hit victims quickly.
You only need the discipline to say “come back in a day or two.”</p>
<h2>This is not enough on its own</h2>
<p>Package maturity gates are not a silver bullet.</p>
<p>You still want the usual boring hygiene:</p>
<ul>
<li>Commit lockfiles</li>
<li>Minimize install-script execution</li>
<li>Pin or carefully review critical dependencies</li>
<li>Keep CI visibility on dependency changes</li>
<li>Use a trusted internal registry or mirror if your environment justifies it</li>
</ul>
<p>Still, I like this mitigation because it is simple and cheap.</p>
<p>A lot of security advice sounds good in a slide deck and then quietly dies because nobody will maintain it.</p>
<p>This one is different.
It is easy to explain, easy to automate, and it specifically targets the dangerous “just published” window that shows up again and again in npm incidents.</p>
<p>The Node ecosystem probably is not going to stop having supply chain attacks.</p>
<p>So the realistic goal is not perfection. The realistic goal is reducing blast radius.</p>
<p>Package maturity gates are one of the simplest ways to do that.</p>]]></content>
    <category term="security" />
    <category term="nodejs" />
  </entry>
  <entry>
    <title>If it&#039;s free; you&#039;re the product (Scraping)</title>
    <link href="https://codewhisperer.dev//posts/if-its-free-youre-the-product-scraping" rel="alternate" type="text/html"/>
    <id>https://codewhisperer.dev//posts/if-its-free-youre-the-product-scraping</id>
    <updated>2025-05-25T00:00:00.000Z</updated>
    <published>2025-05-25T00:00:00.000Z</published>
    <author>
      <name>Itay</name>
    </author>
    <summary type="text">A common phrase, but how does it actually affect us? Intro about scraping and how your computer might be scraping facebook right now.</summary>
    <content type="html"><![CDATA[
<p>Recently I saw someone who created a bot for getting updates on rental apartments. This bot sends Telegram messages based on your parameters such as how many rooms, which city, elevator or not, etc.</p>
<p>I thought this was interesting and wanted to learn a bit about how one would do such a thing.
Quickly I learned that this is unethical and probably not legal and outside the terms of service. But I was still interested in the technical side.</p>
<p>One might think they can simply run some <code>wget</code>/<code>curl</code>/<code>python requests</code> or something similar, but this doesn’t give you the expected results when running against modern websites like Facebook that rely heavily on JavaScript.</p>
<p>Facebook and other sites are basically mini-applications running in your browser. When you visit Facebook, the initial HTML is pretty much empty - everything you see gets loaded by JavaScript after the page loads. So your simple HTTP request just gets you a skeleton page with none of the actual content you’re trying to scrape.</p>
<p>So maybe you’re thinking “okay, I’ll just use browser automation tools like Playwright, Puppeteer, or Selenium to solve this JavaScript problem.” But even if you overcome the dynamic loading, you’ll quickly run into the next wall.</p>
<p>Websites really don’t want you scraping them. They’ll check if you’re making requests too fast, if your browser fingerprint looks suspicious, or if you’re missing those subtle behavioral patterns that make you look human.</p>
<blockquote><p>Some sites will even serve you completely different content if they suspect you’re a bot, or just throw a CAPTCHA at you to stop you dead in your tracks.</p></blockquote>
<p>You might be sneaky and think - Let’s use Lambda or some cloud service so my IP will constantly change. Again, they have probably already faced this issue and you won’t even be able to send a <code>GET</code> request to Facebook from many cloud providers, as Facebook has simply blocked those known IP ranges.</p>
<p>Ok so this is clearly a difficult task, but googling around you can find businesses that seem to sell you the ability to scrape data from Facebook / LinkedIn and other popular websites that contain gold mines of personal information.</p>
<p>I stumbled across the “REDACTED” company which does exactly this. Looking at their website they advertise about having 150 million different residential IP addresses. - <strong>Wow</strong>, how does one get 150 million residential IPs? That would certainly make scraping much easier.</p>
<p>TLDR:
Well the answer, after some digging around, is that some free VPN services, in addition to giving you “free” VPN access, are quietly turning your computer into their slave. They rent out your internet connection to companies who need residential IPs, effectively transforming your home computer into an Facebook stalker or LinkedIn data harvester.</p>
<blockquote><p>You might have seen something similar when installing Adobe Reader in the past, it would auto-select and try to install McAfee on your computer. This is basically that same trick, but even dirtier.</p></blockquote>
<p>Sadly, if something is too good to be true, it probably is.</p>]]></content>
    <category term="scraping tech" />
  </entry>
  <entry>
    <title>Why software can&#039;t be simple</title>
    <link href="https://codewhisperer.dev//posts/why-software-cant-be-simple" rel="alternate" type="text/html"/>
    <id>https://codewhisperer.dev//posts/why-software-cant-be-simple</id>
    <updated>2024-12-09T00:00:00.000Z</updated>
    <published>2024-12-09T00:00:00.000Z</published>
    <author>
      <name>Itay</name>
    </author>
    <summary type="text">The reason for complex software</summary>
    <content type="html"><![CDATA[
<p>Very short summary of excellent video which I recommend watching and added a few comments of my own.
<a href="https://www.youtube.com/watch?v=czzAVuVz7u4" rel="noopener noreferrer" target="_blank">Why Can’t We Make Simple Software? - Peter van Hardenberg</a></p>
<h3>Summary</h3>
<ol>
<li>
<p>Complexity occurs when systems have internal interactions.
It doesn’t mean we have a lot of stuff, internal interactions means when stuff starts getting in the way of each other.</p>
</li>
<li>
<p>Complexity is a natural consequence of a system incentives.
While software evolves you add layers ontop of layers which have internal interactions</p>
</li>
<li>
<p>New tools are not the solution.
Sometimes we reach a point where something is too complex,
so we refactor or rewrite and we are rewarded with a nice feeling and(hopefully) reduced complexity.
Since the software is less complex now, there is less incentive to keep it less complex and it will get more complex because it is easier strap on some additional feature at the cost of refactoring “later”</p>
</li>
</ol>
<blockquote><p>A study was mentioned in the YouTube video that showed that the invention of seatbelts didn’t result in overall less number of casualties per X people.
when wearing seatbelts people feel safer, so they drive faster / take faster turns.
basically, their risk tolerance remains the same, so they drive more recklessly while staying at the same comfortable risk feeling</p></blockquote>
<h3>How to mitigate complexity?</h3>
<ul>
<li>Eliminate dependencies (Do you really need to import that specific library?)</li>
<li>Reduce scope
<ul>
<li>Reduce features and focus on polishing existing flow</li>
<li>Make sure you are not over-engineering - Does the search function really needs caching mechanism or is the data too small to matter?</li>
<li>Does your application really need to support every file type?</li>
</ul>
</li>
<li>Simplify architecture - N X M complexity
<ul>
<li>Do you need to support Windows / Mac / Both?
Firefox / Chrome / Opera / All?
x86 CPU / ARM ?
Each layer multiplies with others which adds many different edge cases</li>
</ul>
</li>
</ul>
<h3>Complexity as an Inevitable Reality</h3>
<p>Peter Van Hardenberg argues that complexity isn’t inherently bad. Emergent behaviors from complex systems, such as the “chemistry engine” in The Legend of Zelda: Breath of the Wild, enable creativity and innovation. However, deliberate and thoughtful management of complexity is essential to avoid pitfalls.</p>
<blockquote><p>“It never gets easier, you just go faster.”
Peter Van Hardenberg</p></blockquote>]]></content>
    <category term="opinion" />
  </entry>
  <entry>
    <title>Fail fast and fail hard</title>
    <link href="https://codewhisperer.dev//posts/fail-fast-and-hard" rel="alternate" type="text/html"/>
    <id>https://codewhisperer.dev//posts/fail-fast-and-hard</id>
    <updated>2024-05-07T00:00:00.000Z</updated>
    <published>2024-05-07T00:00:00.000Z</published>
    <author>
      <name>Itay</name>
    </author>
    <summary type="text">If failing, might aswell just fail fast and hard</summary>
    <content type="html"><![CDATA[
<p>“Fail fast and hard” is a phrase I try to follow when developing and testing a new feature.</p>
<p>This phrase can meet you at many different phases of your work.</p>
<p>When junior developers who are less confident with the codebase and are tasked with fixing some bug or adding a small feature, they will probably have multiple iterations and multiple code reviews until they get their desired result.</p>
<p>But of course, depending on the project, testing and validating your code can be a very expensive operation - Either by time or resources used for running this iteration.</p>
<p>So when applying the phrase for this example, a developer should attempt to make their iterations as quick as possible. There are many ways to accomplish this, depending on your task. I’ll share a few examples below.</p>
<ul>
<li>Developing some Ansible playbook and keep failing on a specific task? No need to run the entire playbook, use <code>--start-at-task</code> to only run your specific task before running the full playbook for final validation.</li>
<li>If you need to iterate by running on some other build server and not locally - Try to find a way to run locally, maybe even creating a small program locally to test your feature (but don’t overdo this).</li>
<li>When developing some software feature, a function or a class for example, use unit testing to be able to quickly validate nothing is broken.</li>
</ul>
<p>The phrase “fail fast and hard” is applicable at so many levels. Let’s look at someone who has an idea for a startup.
Some people can get so invested in trying to get it perfect from the start, choosing the ‘correct’ platform, choosing the ‘perfect’ language.</p>
<p>All of these factors and many more are not the ones which will be the deciding factor of a startup (in the majority of cases). Working to perfect your idea for 3 years only to realize 1 month after release that your idea might need a complete architecture redesign based on the feedback only received now can be a deal breaker and can be too hard to fix.</p>
<p>In my opinion, when working in new and uncharted waters, you should iterate quickly, try to implement your ideas in a hacky way(MVP-Minimal Viable Product) - this will allow you to gather feedback while not going too deep into the rabbit hole and seeing if this idea is worthwhile.</p>
<blockquote><p>This isn’t always the case, the world has many use-cases and sometimes it is worth it to spend extra time.</p></blockquote>]]></content>
    <category term="workflow" />
  </entry>
  <entry>
    <title>The good kind of laziness</title>
    <link href="https://codewhisperer.dev//posts/good-kind-of-laziness" rel="alternate" type="text/html"/>
    <id>https://codewhisperer.dev//posts/good-kind-of-laziness</id>
    <updated>2024-03-25T00:00:00.000Z</updated>
    <published>2024-03-25T00:00:00.000Z</published>
    <author>
      <name>Itay</name>
    </author>
    <summary type="text">You might think being lazy is bad, Being lazy can also mean you don&#039;t want to do repetitive things, and will work toward automating these things...</summary>
    <content type="html"><![CDATA[
<p>Imagine a scenario - a developer is working on some <code>bash</code> script that is supposed to run on a remote test server.</p>
<p>This remote server doesn’t have a GUI, it doesn’t have copilot and doesn’t have our favorite IDE that makes our life sufferable.</p>
<p>So what does this lazy developer do?
He creates the script on his local IDE, <code>CTRL-C</code> the code and <code>CTRL-V</code> into the remote machine - thinking this is a small script that will be ready in no time.
Like usual, estimations are hard. Our developer is not special, and of course, multiple attempts are needed to get the desired result, sometimes dozens of attempts or more.</p>
<p>So each time this lazy developer copies, pastes the code and hopes that this time will be the last one.</p>
<p>This might be a simple task - copy and paste - but don’t underestimate it. This brings needless friction and another pain point to your constantly failing script.</p>
<p>You should always think - especially as a younger developer who is less experienced, how can I make my workflow easier, how can I be lazier? How can I Fail fast and fail hard?</p>
<p>There are multiple solutions to make this workflow more efficient, depending on the tasks and other factors.</p>
<ul>
<li>One solution might be to create a small script on the developer machine (which has the IDE) that will copy the developing script over to the remote test machine and execute it - all automatically.
Meaning the developer will write code, and with 1 click run this script that will copy-paste-run and the developer will see the results as fast as possible.</li>
<li>Another possible solution will be to install an IDE on the remote test machine or even work using <code>nano</code> or <code>vim</code>.
This should only be considered in very rare cases as it might lead to lost code that is not checked out to a SCM (Github/Bitbucket/etc).</li>
<li>If the development task is complicated and also has dependencies or a build stage (for example, building multiple Docker containers, removing the old ones, etc..), it is probably worth developing some pipeline such as GitHub Actions, Jenkins, or a bash script.</li>
</ul>]]></content>
    <category term="workflow" />
  </entry>
</feed>