From 8941a363c3ffd417c3c72fbabbbaaf99745c9e12 Mon Sep 17 00:00:00 2001 From: Dylan Conway Date: Wed, 17 Dec 2025 19:56:25 -0800 Subject: [PATCH] fix: dupe `ca` string in .npmrc to prevent use-after-free (#25563) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Fix use-after-free bug when parsing `ca` option from `.npmrc` - The `ca` string was being stored directly from the parser's arena without duplication - Since the parser arena is freed at the end of `loadNpmrc`, this created a dangling pointer ## The Bug In `src/ini.zig`, the `ca` string wasn't being duplicated like all other string properties: ```zig // Lines 983-986 explicitly warn about this: // Need to be very, very careful here with strings. // They are allocated in the Parser's arena, which of course gets // deinitialized at the end of the scope. // We need to dupe all strings // Line 981: Parser arena is freed here defer parser.deinit(); // Line 1016-1020: THE BUG - string not duped! if (out.asProperty("ca")) |query| { if (query.expr.asUtf8StringLiteral()) |str| { install.ca = .{ .str = str, // ← Dangling pointer after parser.deinit()! }; ``` All other string properties in the same function correctly duplicate: - `registry` (line 996): `try allocator.dupe(u8, str)` - `cache` (line 1002): `try allocator.dupe(u8, str)` - `cafile` (line 1037): `asStringCloned(allocator)` - `ca` array items (line 1026): `asStringCloned(allocator)` ## User Impact When a user has `ca=` in their `.npmrc` file: 1. The certificate string is parsed and stored 2. The parser arena is freed 3. `install.ca.str` becomes a dangling pointer 4. Later TLS/SSL operations access freed memory 5. Could cause crashes, undefined behavior, or security issues ## Test plan - Code inspection confirms this matches the pattern used for all other string properties - The fix adds `try allocator.dupe(u8, str)` to match `cache`, `registry`, etc. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude --- src/ini.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ini.zig b/src/ini.zig index 4e74e83907..23e8b57380 100644 --- a/src/ini.zig +++ b/src/ini.zig @@ -1016,7 +1016,7 @@ pub fn loadNpmrc( if (out.asProperty("ca")) |query| { if (query.expr.asUtf8StringLiteral()) |str| { install.ca = .{ - .str = str, + .str = try allocator.dupe(u8, str), }; } else if (query.expr.isArray()) { const arr = query.expr.data.e_array;