<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: andrew-nesbitt</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/andrew-nesbitt.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2026-06-26T17:58:54+00:00</updated><author><name>Simon Willison</name></author><entry><title>Incident Report: CVE-2026-LGTM</title><link href="https://simonwillison.net/2026/Jun/26/incident-report/#atom-tag" rel="alternate"/><published>2026-06-26T17:58:54+00:00</published><updated>2026-06-26T17:58:54+00:00</updated><id>https://simonwillison.net/2026/Jun/26/incident-report/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://nesbitt.io/2026/06/26/incident-report-cve-2026-lgtm.html"&gt;Incident Report: CVE-2026-LGTM&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Spectacular hypothetical incident report by Andrew Nesbitt.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Day 2, 16:00 UTC&lt;/strong&gt; --- Two AI review agents from competing vendors, both attached to a downstream pull request bumping &lt;code&gt;foxhole-lz4&lt;/code&gt;, enter a disagreement loop over whether the package is malicious. After 340 comments and $41,255 in inference spend, Finance revokes both API keys; one vendor's marketing team, cc'd on the cost anomaly alert, issues a press release citing "a 430% YoY increase in adversarial multi-agent security reasoning." The stock opens up 6%.&lt;/p&gt;
&lt;/blockquote&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/prompt-injection"&gt;prompt-injection&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/supply-chain"&gt;supply-chain&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-security-research"&gt;ai-security-research&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/andrew-nesbitt"&gt;andrew-nesbitt&lt;/a&gt;&lt;/p&gt;



</summary><category term="security"/><category term="ai"/><category term="prompt-injection"/><category term="generative-ai"/><category term="llms"/><category term="supply-chain"/><category term="ai-security-research"/><category term="andrew-nesbitt"/></entry><entry><title>Package Managers Need to Cool Down</title><link href="https://simonwillison.net/2026/Mar/24/package-managers-need-to-cool-down/#atom-tag" rel="alternate"/><published>2026-03-24T21:11:38+00:00</published><updated>2026-03-24T21:11:38+00:00</updated><id>https://simonwillison.net/2026/Mar/24/package-managers-need-to-cool-down/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://nesbitt.io/2026/03/04/package-managers-need-to-cool-down.html"&gt;Package Managers Need to Cool Down&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Today's &lt;a href="https://simonwillison.net/2026/Mar/24/malicious-litellm/"&gt;LiteLLM supply chain attack&lt;/a&gt; inspired me to revisit the idea of &lt;a href="https://simonwillison.net/2025/Nov/21/dependency-cooldowns/"&gt;dependency cooldowns&lt;/a&gt;, the practice of only installing updated dependencies once they've been out in the wild for a few days to give the community a chance to spot if they've been subverted in some way.&lt;/p&gt;
&lt;p&gt;This recent piece (March 4th) piece by Andrew Nesbitt reviews the current state of dependency cooldown mechanisms across different packaging tools. It's surprisingly well supported! There's been a flurry of activity across major packaging tools, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pnpm.io/blog/releases/10.16#new-setting-for-delayed-dependency-updates"&gt;pnpm 10.16&lt;/a&gt; (September 2025) — &lt;code&gt;minimumReleaseAge&lt;/code&gt; with &lt;code&gt;minimumReleaseAgeExclude&lt;/code&gt; for trusted packages&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yarnpkg/berry/releases/tag/%40yarnpkg%2Fcli%2F4.10.0"&gt;Yarn 4.10.0&lt;/a&gt; (September 2025) — &lt;code&gt;npmMinimalAgeGate&lt;/code&gt; (in minutes) with &lt;code&gt;npmPreapprovedPackages&lt;/code&gt; for exemptions&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bun.com/blog/bun-v1.3#minimum-release-age"&gt;Bun 1.3&lt;/a&gt; (October 2025) — &lt;code&gt;minimumReleaseAge&lt;/code&gt; via &lt;code&gt;bunfig.toml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://deno.com/blog/v2.6#controlling-dependency-stability"&gt;Deno 2.6&lt;/a&gt; (December 2025) — &lt;code&gt;--minimum-dependency-age&lt;/code&gt; for &lt;code&gt;deno update&lt;/code&gt; and &lt;code&gt;deno outdated&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/astral-sh/uv/releases/tag/0.9.17"&gt;uv 0.9.17&lt;/a&gt; (December 2025) — added relative duration support to existing &lt;code&gt;--exclude-newer&lt;/code&gt;, plus per-package overrides via &lt;code&gt;exclude-newer-package&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ichard26.github.io/blog/2026/01/whats-new-in-pip-26.0/"&gt;pip 26.0&lt;/a&gt; (January 2026) — &lt;code&gt;--uploaded-prior-to&lt;/code&gt; (absolute timestamps only; &lt;a href="https://github.com/pypa/pip/issues/13674"&gt;relative duration support requested&lt;/a&gt;, &lt;strong&gt;update&lt;/strong&gt;: and added &lt;a href="https://ichard26.github.io/blog/2026/04/whats-new-in-pip-26.1/"&gt;in pip 26.1 in April&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://socket.dev/blog/npm-introduces-minimumreleaseage-and-bulk-oidc-configuration"&gt;npm 11.10.0&lt;/a&gt; (February 2026) — &lt;code&gt;min-release-age&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;pip&lt;/code&gt; currently only supports absolute rather than relative dates but Seth Larson &lt;a href="https://sethmlarson.dev/pip-relative-dependency-cooling-with-crontab"&gt;has a workaround for that&lt;/a&gt; using a scheduled cron to update the absolute date in the &lt;code&gt;pip.conf&lt;/code&gt; config file.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/packaging"&gt;packaging&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pip"&gt;pip&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pypi"&gt;pypi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/npm"&gt;npm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deno"&gt;deno&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/supply-chain"&gt;supply-chain&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/uv"&gt;uv&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/andrew-nesbitt"&gt;andrew-nesbitt&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="packaging"/><category term="pip"/><category term="pypi"/><category term="python"/><category term="security"/><category term="npm"/><category term="deno"/><category term="supply-chain"/><category term="uv"/><category term="andrew-nesbitt"/></entry><entry><title>How uv got so fast</title><link href="https://simonwillison.net/2025/Dec/26/how-uv-got-so-fast/#atom-tag" rel="alternate"/><published>2025-12-26T23:43:15+00:00</published><updated>2025-12-26T23:43:15+00:00</updated><id>https://simonwillison.net/2025/Dec/26/how-uv-got-so-fast/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://nesbitt.io/2025/12/26/how-uv-got-so-fast.html"&gt;How uv got so fast&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Andrew Nesbitt provides an insightful teardown of why &lt;a href="https://github.com/astral-sh/uv"&gt;uv&lt;/a&gt; is so much faster than &lt;code&gt;pip&lt;/code&gt;. It's not nearly as simple as just "they rewrote it in Rust" - &lt;code&gt;uv&lt;/code&gt; gets to skip a huge amount of Python packaging history (which &lt;code&gt;pip&lt;/code&gt; needs to implement for backwards compatibility) and benefits enormously from work over recent years that makes it possible to resolve dependencies across most packages without having to execute the code in &lt;code&gt;setup.py&lt;/code&gt; using a Python interpreter.&lt;/p&gt;
&lt;p&gt;Two notes that caught my eye that I hadn't understood before:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;HTTP range requests for metadata.&lt;/strong&gt; &lt;a href="https://packaging.python.org/en/latest/specifications/binary-distribution-format/"&gt;Wheel files&lt;/a&gt; are zip archives, and zip archives put their file listing at the end. uv tries PEP 658 metadata first, falls back to HTTP range requests for the zip central directory, then full wheel download, then building from source. Each step is slower and riskier. The design makes the fast path cover 99% of cases. None of this requires Rust.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compact version representation&lt;/strong&gt;. uv packs versions into u64 integers where possible, making comparison and hashing fast. Over 90% of versions fit in one u64. This is micro-optimization that compounds across millions of comparisons.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I wanted to learn more about these tricks, so I fired up &lt;a href="https://simonwillison.net/2025/Nov/6/async-code-research/"&gt;an asynchronous research task&lt;/a&gt; and told it to checkout the &lt;code&gt;astral-sh/uv&lt;/code&gt; repo, find the Rust code for both of those features and try porting it to Python to help me understand how it works.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://github.com/simonw/research/tree/main/http-range-wheel-metadata"&gt;the report that it wrote for me&lt;/a&gt;, the &lt;a href="https://github.com/simonw/research/pull/57"&gt;prompts I used&lt;/a&gt; and the &lt;a href="https://gistpreview.github.io/?0f04e4d1a240bfc3065df5082b629884/index.html"&gt;Claude Code transcript&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can try &lt;a href="https://github.com/simonw/research/blob/main/http-range-wheel-metadata/wheel_metadata.py"&gt;the script&lt;/a&gt; it wrote for extracting metadata from a wheel using HTTP range requests like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;uv run --with httpx https://raw.githubusercontent.com/simonw/research/refs/heads/main/http-range-wheel-metadata/wheel_metadata.py https://files.pythonhosted.org/packages/8b/04/ef95b67e1ff59c080b2effd1a9a96984d6953f667c91dfe9d77c838fc956/playwright-1.57.0-py3-none-macosx_11_0_arm64.whl -v&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The Playwright wheel there is ~40MB. Adding &lt;code&gt;-v&lt;/code&gt; at the end causes the script to spit out verbose details of how it fetched the data - &lt;a href="https://gist.github.com/simonw/a5ef83b6e4605d2577febb43fa9ad018"&gt;which looks like this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Key extract from that output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[1] HEAD request to get file size...
    File size: 40,775,575 bytes
[2] Fetching last 16,384 bytes (EOCD + central directory)...
    Received 16,384 bytes
[3] Parsed EOCD:
    Central directory offset: 40,731,572
    Central directory size: 43,981
    Total entries: 453
[4] Fetching complete central directory...
    ...
[6] Found METADATA: playwright-1.57.0.dist-info/METADATA
    Offset: 40,706,744
    Compressed size: 1,286
    Compression method: 8
[7] Fetching METADATA content (2,376 bytes)...
[8] Decompressed METADATA: 3,453 bytes

Total bytes fetched: 18,760 / 40,775,575 (100.0% savings)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The section of the report &lt;a href="https://github.com/simonw/research/tree/main/http-range-wheel-metadata#bonus-compact-version-representation"&gt;on compact version representation&lt;/a&gt; is interesting too. Here's how it illustrates sorting version numbers correctly based on their custom u64 representation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Sorted order (by integer comparison of packed u64):
  1.0.0a1 (repr=0x0001000000200001)
  1.0.0b1 (repr=0x0001000000300001)
  1.0.0rc1 (repr=0x0001000000400001)
  1.0.0 (repr=0x0001000000500000)
  1.0.0.post1 (repr=0x0001000000700001)
  1.0.1 (repr=0x0001000100500000)
  2.0.0.dev1 (repr=0x0002000000100001)
  2.0.0 (repr=0x0002000000500000)
&lt;/code&gt;&lt;/pre&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sorting"&gt;sorting&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/uv"&gt;uv&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/http-range-requests"&gt;http-range-requests&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vibe-porting"&gt;vibe-porting&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/andrew-nesbitt"&gt;andrew-nesbitt&lt;/a&gt;&lt;/p&gt;



</summary><category term="performance"/><category term="python"/><category term="sorting"/><category term="rust"/><category term="uv"/><category term="http-range-requests"/><category term="vibe-porting"/><category term="andrew-nesbitt"/></entry><entry><title>Quoting Andrew Nesbitt</title><link href="https://simonwillison.net/2025/Apr/12/andrew-nesbitt/#atom-tag" rel="alternate"/><published>2025-04-12T16:30:07+00:00</published><updated>2025-04-12T16:30:07+00:00</updated><id>https://simonwillison.net/2025/Apr/12/andrew-nesbitt/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://mastodon.social/@andrewnez/114302875075999244"&gt;&lt;p&gt;&lt;strong&gt;Slopsquatting&lt;/strong&gt; -- when an LLM hallucinates a non-existent package name, and a bad actor registers it maliciously. The AI brother of typosquatting.&lt;/p&gt;
&lt;p&gt;Credit to &lt;a href="https://fosstodon.org/@sethmlarson" title="@sethmlarson"&gt;@sethmlarson&lt;/a&gt; for the name&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://mastodon.social/@andrewnez/114302875075999244"&gt;Andrew Nesbitt&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/definitions"&gt;definitions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/packaging"&gt;packaging&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/supply-chain"&gt;supply-chain&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/slop"&gt;slop&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/seth-michael-larson"&gt;seth-michael-larson&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/andrew-nesbitt"&gt;andrew-nesbitt&lt;/a&gt;&lt;/p&gt;



</summary><category term="definitions"/><category term="packaging"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="supply-chain"/><category term="slop"/><category term="ai-ethics"/><category term="seth-michael-larson"/><category term="andrew-nesbitt"/></entry></feed>