Hide sensitive values in configuration files during screen sharing.
A Neovim plugin that visually masks secrets in .env, .json, .yaml, .toml, .properties, .netrc, .xml, .http, Terraform/HCL (.tf, .tfvars, .hcl), and Dockerfile files using extmarks - without modifying the actual file content.

.env, .json, .yaml, .yml, .toml, .properties, .ini, .conf, .sh, .netrc, .xml, .http, .tf, .tfvars, .hcl, Dockerfile, Containerfiledatabase.connection.password in JSON/YAML/XMLstars, dotted, text, scrambleexp claim and show "expires in 2h" badgescamouflage hides sensitive values visually, by drawing over them with virtual text. It does not change the file, and it does not encrypt or remove anything.
It protects against casual exposure of secrets on screen: shoulder-surfing, screen sharing, pair programming, screenshots, and demos.
It does not protect against anything that reads the buffer or file contents directly, because the real text is still there underneath the mask:
live_grep result lines
(only the preview buffer is masked, not the matched result rows):%print, :substitute previews, :w/:saveas, and yanking with yy/"+y+/* clipboard registers (use :CamouflageYank, which copies the real
value deliberately with a confirm prompt and timed auto-clear)For per-repo .camouflage.yaml files, masking config is applied as data only
(no code execution). If you don't trust the repositories you open, set
project_config.secure = true to gate the file behind Neovim's
vim.secure/:trust mechanism.
The scramble style is cosmetic, not protective: the mask is a shuffle of
the real characters, so it leaks the value's length and character set.
{
'zeybek/camouflage.nvim',
event = 'VeryLazy',
opts = {},
keys = {
{ '<leader>ct', '<cmd>CamouflageToggle<cr>', desc = 'Toggle Camouflage' },
{ '<leader>cr', '<cmd>CamouflageReveal<cr>', desc = 'Reveal Line' },
{ '<leader>cy', '<cmd>CamouflageYank<cr>', desc = 'Yank Value' },
{ '<leader>cf', '<cmd>CamouflageFollowCursor<cr>', desc = 'Follow Cursor' },
},
}
use {
'zeybek/camouflage.nvim',
config = function()
require('camouflage').setup()
end
}
Plug 'zeybek/camouflage.nvim'
" In your init.lua or after/plugin/camouflage.lua:
lua require('camouflage').setup()
local add = MiniDeps.add
add({
source = 'zeybek/camouflage.nvim',
})
require('camouflage').setup()
git clone https://github.com/zeybek/camouflage.nvim.git \
~/.local/share/nvim/site/pack/plugins/start/camouflage.nvim
Then add to your init.lua:
require('camouflage').setup()
The plugin works with zero configuration. Here's a quick overview of common options:
require('camouflage').setup({
enabled = true,
auto_enable = true,
style = 'stars', -- 'text' | 'dotted' | 'stars' | 'scramble'
mask_char = '*',
debounce_ms = 150,
max_lines = 5000,
reveal = {
follow_cursor = false, -- Auto-reveal current line
},
yank = {
confirm = true, -- Require confirmation before copying
auto_clear_seconds = 30, -- Auto-clear clipboard
},
integrations = {
telescope = true,
cmp = { disable_in_masked = true },
},
})
Full configuration reference on the wiki.
| Command | Description |
|---|---|
:CamouflageToggle |
Toggle camouflage on/off |
:CamouflageReveal |
Reveal masked values on current line |
:CamouflageYank |
Copy unmasked value at cursor to clipboard |
:CamouflageFollowCursor |
Toggle follow cursor mode |
:CamouflageStatus |
Show status and masked count |
:CamouflageRefresh |
Refresh decorations |
:CamouflagePwnedCheck |
Check if value under cursor is pwned |
:CamouflagePwnedCheckBuffer |
Check all values in buffer |
:CamouflageExpiryToggle |
Toggle JWT expiry check on/off |
:CamouflageInit |
Create .camouflage.yaml in project root |
:CamouflageParsers |
List registered parsers (debug) |
Full commands list on the wiki.
| Format | Extensions | Nested Keys |
|---|---|---|
| Environment | .env, .env.*, .envrc, .sh |
No |
| JSON | .json |
Yes |
| YAML | .yaml, .yml |
Yes |
| TOML | .toml |
Yes (sections) |
| Properties | .properties, .ini, .conf, credentials |
Yes (sections) |
| Netrc | .netrc, _netrc |
No |
| XML | .xml |
Yes |
| HTTP | .http |
No |
| HCL / Terraform | .tf, .tfvars, .hcl |
Yes |
| Dockerfile | Dockerfile, Containerfile, *.dockerfile |
No |
For unsupported formats, you can define custom patterns.
For detailed documentation, visit the Wiki:
.camouflage.yamlYou can also use :help camouflage within Neovim.
MIT License - see LICENSE for details.