Hide sensitive values in configuration files during screen sharing.
camouflage.nvim draws a mask over API keys, passwords and tokens in .env, JSON, YAML, TOML, Terraform, Dockerfiles and more, as the file opens. The file itself is never changed.

A longer tour, with the audit, terminal masking and presentation mode, is on the wiki.
database.connection.password)git commit -v, and :terminal output if you turn it on:CamouflagePresent masks everything and refuses reveals for the length of a demo, and :CamouflageShield covers the whole editor until you press a key[weak: default]), shows when a JWT expires, and checks passwords against Have I Been Pwned when you ask it to:CamouflageAudit lists every masked key in a project, never the value, with JSON output and an exit code for CI.camouflage.yaml, including data-only rules for what to mask and howWith lazy.nvim:
{
'zeybek/camouflage.nvim',
event = { 'BufReadPre', 'BufNewFile' },
opts = {},
keys = {
{ '<leader>mt', '<cmd>CamouflageToggle<cr>', desc = 'Toggle Camouflage' },
{ '<leader>mr', '<cmd>CamouflageReveal<cr>', desc = 'Reveal Line' },
{ '<leader>my', '<cmd>CamouflageYank<cr>', desc = 'Yank Value' },
{ '<leader>mf', '<cmd>CamouflageFollowCursor<cr>', desc = 'Follow Cursor' },
},
}
BufReadPre/BufNewFile loads it as the first file opens, so no buffer is drawn before it's masked. The keys sit under <leader>m because LazyVim and AstroNvim already use <leader>c.
rocks.nvim, from LuaRocks:
:Rocks install camouflage.nvim
use {
'zeybek/camouflage.nvim',
config = function()
require('camouflage').setup()
end
}
Plug 'zeybek/camouflage.nvim'
MiniDeps.add({ source = 'zeybek/camouflage.nvim' })
By hand:
git clone https://github.com/zeybek/camouflage.nvim.git \
~/.local/share/nvim/site/pack/plugins/start/camouflage.nvim
Everything except lazy.nvim's opts and packer's config also needs require('camouflage').setup() in your config.
Open a supported file and its values are masked. These are the commands you'll use most:
| Command | What it does |
|---|---|
:CamouflageToggle |
Turn masking on or off |
:CamouflageReveal |
Show the values on the current line until the cursor leaves it |
:CamouflageFollowCursor |
Keep the line under the cursor revealed as you move |
:CamouflageYank |
Copy the value under the cursor, after a prompt, and clear it after 30s |
:CamouflagePresent |
Presentation mode: everything masked, reveals refused (! to leave) |
:CamouflageShield |
Cover the whole editor until a key is pressed |
:CamouflageAudit |
List every masked key in the project in the quickfix list |
:CamouflageStatus |
Show whether this buffer is masked, by which parser, and how many values |
There are 22 in all, see Commands and Keymaps. If a file isn't masked the way you expect, :checkhealth camouflage says why, without printing any value.
It works without any configuration. These are the options people change most, shown with their defaults:
require('camouflage').setup({
style = 'stars', -- 'stars' | 'dotted' | 'text' | 'scramble'
reveal = { follow_cursor = false },
yank = { confirm = true, auto_clear_seconds = 30 },
terminal = { enabled = false }, -- mask KEY=value output in :terminal
shield = { on_focus_lost = false }, -- cover the editor when it loses focus
pwned = { auto_check = false }, -- Have I Been Pwned on BufEnter, sends a request
})
Every option is in the Configuration reference and in :help camouflage-configuration.
camouflage hides values visually, by drawing over them. It doesn't encrypt, remove or change anything, and the real text is still in the buffer. That covers the screen: screen sharing, pair programming, recordings and someone looking over your shoulder.
It doesn't cover anything that reads the buffer or the file:
yy or "+y, the clipboard, and :registers (:CamouflageYank and :CamouflageRegisters are the careful versions):%print, :substitute previews, saved files, backups, swap and undo files(1 of 3): API_KEY=...scramble only shuffles the real characters, so it shows the value's length and character set. A .camouflage.yaml is data only. It can't run code or set the shield, and it can't turn on network checks unless you trust it. The Security Model page has the full list and the workarounds.
:CamouflageInit writes a .camouflage.yaml for the project. Rules in it, or in setup(), decide which found values are masked and how:
version: 1
policy:
terminal_path_ignores: ['tests/fixtures/**']
rules:
- id: ignore-debug
action: ignore
key: ['^DEBUG$', '^PORT$']
- id: aws-key-id
action: mask
key: ['^AWS_ACCESS_KEY_ID$']
style: partial
show_end: 4
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE then shows as ****************MPLE. Key patterns are case-sensitive Lua patterns, and ignore_case: true on a rule makes a lower-case pattern match any case. See Project Config and Rule Based Policy.
nvim --headless -c 'CamouflageAudit --json=audit.json --quit .'
writes every finding (file, line, key, value length, policy decision) to audit.json and exits with 1 when there is one. No value is written anywhere. See Workspace Audit.
| Format | Files | Nested keys |
|---|---|---|
| Environment | .env, .env.*, *.env, .envrc, *.sh |
No |
| JSON | *.json, *.jsonc |
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 |
Yes (headers, query, JSON body) |
| HCL / Terraform | *.tf, *.tfvars, *.hcl |
Yes |
| Dockerfile | Dockerfile, Dockerfile.*, *.dockerfile, Containerfile, Containerfile.* |
No |
Formats with a TreeSitter grammar use it when it's installed, and every format works without it. For another format, add a Lua pattern with custom_patterns or register a parser.
The formats above need no patterns. Each one has a parser that finds values by their key, so there's nothing to write for them. The rest maps like this:
| cloak.nvim | camouflage.nvim |
|---|---|
cloak_character = '*' |
mask_char = '*' |
highlight_group = 'Comment' |
highlight_group = 'Comment' |
cloak_length = 8 |
mask_length = 8 |
cloak_telescope = true |
integrations.telescope = true (the default) |
patterns for another file type |
custom_patterns |
:CloakToggle |
:CamouflageToggle |
:CloakPreviewLine |
:CamouflageReveal |
Like cloak, it turns nvim-cmp off in masked buffers, and blink.cmp too.
The wiki has a page for every feature, and :help camouflage covers the same ground inside Neovim. Good places to start:
MIT, see LICENSE.