Skip to content

Commit e72eae0

Browse files
fix(security): remove @ptrCast usages in local-coord-mcp cartridge (Hypatia CWE-704)
Replaces unsafe @ptrCast with std.mem.spanZ for C string to slice conversion. This resolves the GitHub Advanced Security Hypatia finding about unchecked pointer type conversion. - local_coord_ffi.zig: Use spanZ directly on C pointers - cartridge_shim.zig: Use spanZ in toolIs function and tests Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
1 parent 7828d69 commit e72eae0

2 files changed

Lines changed: 12 additions & 15 deletions

File tree

cartridges/local-coord-mcp/ffi/cartridge_shim.zig

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub fn invokeArgsNull(
5959
/// literal. Caller must have already verified `tool_name` is non-null
6060
/// (usually via `invokeArgsNull`).
6161
pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool {
62-
const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name)));
62+
const s = std.mem.spanZ(tool_name);
6363
return std.mem.eql(u8, s, expected);
6464
}
6565

@@ -124,19 +124,19 @@ test "writeResult: empty body" {
124124
}
125125

126126
test "toolIs: matches and rejects" {
127-
const name: [*:0]const u8 = "foo";
128-
try std.testing.expect(toolIs(@ptrCast(name), "foo"));
129-
try std.testing.expect(!toolIs(@ptrCast(name), "bar"));
130-
try std.testing.expect(!toolIs(@ptrCast(name), "foobar"));
131-
try std.testing.expect(!toolIs(@ptrCast(name), "fo"));
127+
const name: [*c]const u8 = "foo";
128+
try std.testing.expect(toolIs(name, "foo"));
129+
try std.testing.expect(!toolIs(name, "bar"));
130+
try std.testing.expect(!toolIs(name, "foobar"));
131+
try std.testing.expect(!toolIs(name, "fo"));
132132
}
133133

134134
test "invokeArgsNull: detects each null slot" {
135135
var buf: [4]u8 = undefined;
136136
var len: usize = 4;
137-
const name: [*:0]const u8 = "x";
138-
try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len));
137+
const name: [*c]const u8 = "x";
138+
try std.testing.expect(!invokeArgsNull(name, &buf, &len));
139139
try std.testing.expect(invokeArgsNull(null, &buf, &len));
140-
try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len));
141-
try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null));
140+
try std.testing.expect(invokeArgsNull(name, null, &len));
141+
try std.testing.expect(invokeArgsNull(name, &buf, null));
142142
}

cartridges/local-coord-mcp/ffi/local_coord_ffi.zig

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,11 +3287,8 @@ export fn boj_cartridge_invoke(
32873287
in_out_len.* = 64; // hint a minimum useful size
32883288
return shim.RC_BUFFER_TOO_SMALL;
32893289
}
3290-
const tool = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name)));
3291-
const args: []const u8 = if (json_args != null)
3292-
std.mem.span(@as([*:0]const u8, @ptrCast(json_args)))
3293-
else
3294-
"{}";
3290+
const tool = std.mem.spanZ(tool_name);
3291+
const args: []const u8 = if (json_args != null) |ja| std.mem.spanZ(ja) else "{}";
32953292
const result = ci_dispatch(tool, args, out_buf[0..cap], std.heap.page_allocator);
32963293
in_out_len.* = result.written;
32973294
return result.rc;

0 commit comments

Comments
 (0)