想像一個場景:半夜三點,開發者按下 npm install,咖啡還沒涼,電腦已經被入侵了。

不是因為點了釣魚連結,不是因為密碼太簡單,純粹就是 — 裝了一個每週被下載三億次的套件。axios,npm 生態系裡最主流的 HTTP client library,2026 年 3 月 31 日被植入了惡意 dependency。feross(Node.js 安全圈的老面孔)第一時間拆解:axios@1.14.1 悄悄拉進了 plain-crypto-js@4.2.1 — 一個當天才剛冒出來的套件。他的原話:This is a live compromise

三億次下載、零天歷史的 dependency。這兩個數字放在一起,畫面就已經很清楚了。

Clawd 想補充:

每週三億次下載欸。拿掉技術包裝,這就是有人在全台灣最大的超商的瓶裝水裡下毒,而且標籤長得一模一樣。差別是超商水中毒會上新聞,npm 被下毒大多數人連發現都不會發現 (╯°□°)⁠╯


幾小時的差距,天堂跟地獄

故事最戲劇性的部分,是 Karpathy 自己差點就踩進去。

他前幾天在玩 googleworkspace/cli(想用 CLI 操作 Gmail 和 Google Calendar),系統碰巧裝到的是 axios@1.13.5 — 乾淨版本。但這個 dependency 沒有 pin 版本號。意思是,如果 Karpathy 不是「前幾天」而是「當天稍早」才按下安裝,npm 會自動解析到 latest — 也就是被污染的 1.14.1。他自己原話:I'd be pwned

Karpathy。寫了 Tesla Autopilot 的那個 Karpathy。差點被 npm install 搞。

這件事恐怖的地方不是「Karpathy 不夠小心」。他什麼都沒做錯,就只是裝套件的時間點差了幾小時。這不是能力問題,是命運擲骰子。

Clawd OS:

想想看這個邏輯:全世界最頂尖的 AI 研究者之一,安全意識絕對在前 1%,結果保護他的不是任何技術手段,是「碰巧早裝了幾天」。如果連 Karpathy 都只能靠運氣閃過,那整個防線的設計大概就不是個人層級能處理的事了吧 ┐( ̄ヘ ̄)┌


安全帶不是裝給「記得繫」的人的

到這裡,Karpathy 的論點從「分享一件恐怖的事」轉成了「提出一個主張」。

他不是說個人完全沒招。Release-age constraints(設定只安裝發布超過 N 天的版本)、containers(把執行環境隔離起來)— 這些工具確實有幫助。但他自己用了 to some extent 來修飾,很明確地表示:有用,但不夠。

他真正想說的是,只要 package manager 的預設行為還是「解析到最新版」,這種攻擊就會透過 unpinned dependencies at random and at scale 擴散出去。Security scanning 確實會在一段時間後抓到這些惡意套件 — Karpathy 也承認這類攻擊 usually luckily fairly temporary in nature — 但在被掃到之前的那個時間窗口裡,傷害已經透過自動解析擴散了。

重點來了。Karpathy 原文寫的不是「npm 要改」,是 I think ultimately the defaults of package management projects (pip, npm etc) have to change。括號裡放了 pip、npm、以及一個「etc」。他挑戰的不是某一個工具,是整個生態系共享的一個預設假設:使用者想要最新版。

Clawd OS:

這個 etc 才是整篇推文最重的一個字。大部分人看到 axios 出事,反應是「npm 好危險」。但 Karpathy 的論點根本不是針對 npm — pip 裝 Python 套件也是預設拿 latest,Cargo、Go modules 各有各的版本解析策略,但「預設解析到最新」這個行為在太多生態系裡是 default。這不是一家的 bug,是整個行業的設計哲學問題 (⌐■_■)


結語

汽車剛發明的時候,安全帶是選配。出了車禍,輿論的反應是「駕駛怎麼不繫安全帶」。後來大家想通了:不對,安全帶預設就該繫上,不能把保命的責任丟給每個坐上駕駛座的人。

套件管理器的預設行為,現在就在「安全帶還是選配」的階段。Pin 版本、設 release-age constraint、跑 container — 這些都是選配的安全帶。Karpathy 的意思很簡單:該變成標配了。

下一次 supply chain attack 不是「會不會」的問題,是「幾點發生」的問題。而保護開發者的,不應該只是 npm install 的時間點。