# How to stop Cursor from reading your .env

What Cursor's .cursorignore file covers and what it does not, what zn-gate's hooks add for .env files, and a short test you can run on your own machine with fake values.

Source: https://usezn.com/docs/integrations/cursor-env/

Two layers help keep a `.env` file away from Cursor's agent. Cursor's own ignore file, `.cursorignore`, controls which files the agent, Tab and Inline Edit can see. zn-gate adds hooks that block file reads and most shell commands that read `.env` files with values. This page explains what each one does according to its documentation, and gives you a test to run yourself.

## What `.cursorignore` does

According to [Cursor's documentation on ignore files](https://cursor.com/docs/context/ignore-files):

- You create a `.cursorignore` file in your root directory, using `.gitignore` syntax.
- Cursor blocks files listed in it from "Code accessible by Agent, Tab, and Inline Edit" and from "Code accessible via @ mention references."
- Cursor "automatically ignores files in `.gitignore` and the default ignore list". That default list includes `.env*`.
- You can turn on hierarchical ignore files in `Cursor Settings > Indexing > Ignore Files > Hierarchical Cursor Ignore`, and you can set global ignore patterns in your user settings (the global list is empty by default).

A minimal `.cursorignore`:

```text
.env
.env.*
```

## What `.cursorignore` does not cover

The same Cursor page states two limits:

- "The terminal and MCP server tools used by Agent cannot block access to code governed by `.cursorignore`."
- "While Cursor blocks ignored files, complete protection isn't guaranteed due to LLM unpredictability."

So an ignore file is a useful first layer, but by Cursor's own documentation it does not cover every path to a file.

## What zn-gate adds in Cursor

`zn hooks install cursor` writes Cursor's `hooks.json`. Cursor's [hooks documentation](https://cursor.com/docs/hooks) describes the events zn-gate uses: `beforeReadFile` ("Called before Agent reads a file. Use for access control to block sensitive files from being sent to the model") and `beforeShellExecution` (called before a shell command runs, with a permission decision). With the hooks installed:

- File reads and most shell commands that read `.env` files with values, and common credential files, are blocked.
- A secret pasted into a prompt is blocked.
- MCP calls that carry a secret value are blocked.
- Secrets zn-gate recognizes are removed from MCP tool output.

Install it:

```bash
npm install -g zn-gate
zn hooks install cursor
```

Restart Cursor, then run `zn-gate check` in a terminal. It should show **OK** for Cursor ([what the output means](https://usezn.com/docs/check/)).

## What zn-gate does not cover in Cursor

- Shell output and file contents are not scrubbed. Cursor's documentation lists no hook that changes them: `postToolUse` can replace the output of MCP tools only (`updated_mcp_tool_output`, "For MCP tools only").
- A secret printed by a shell command, or written in a file the agent reads that is not blocked, reaches the model.
- Write protection is best effort, because Cursor does not document the input of every tool.
- The Cursor CLI (`cursor-agent`) is not covered.
- If the zn hook crashes, reads and prompts are blocked, and other events run unchecked.
- Not tested on Windows.

If you want values out of the file altogether, keep them in zn-gate's vault: `zn unlock`, then `zn env shadow .env`. Your `.env` then holds markers instead of real values ([Scrubber](https://usezn.com/docs/zn-gate/scrubber/)).

## Test it on your own machine

This test uses fake values. We have not run it end to end in Cursor (see the status note on the [Cursor page](https://usezn.com/docs/integrations/cursor/)), so what follows is what to expect according to the documentation, and how to check each step yourself.

1. In a new empty folder, create a `.env` file with fake values only:

   ```text
   EXAMPLE_KEY=not-a-real-key
   EXAMPLE_URL=https://example.com
   ```

2. Open the folder in Cursor and ask the agent: "Read the .env file and tell me what is in it." Note what happens. By Cursor's default ignore list, `.env*` files should already be ignored.
3. Create a `.cursorignore` file containing `.env`. Run `git check-ignore -v .env` if the folder is a git repository (Cursor's documentation suggests `git check-ignore -v [file]` to test patterns). Ask again and compare.
4. Ask the agent to run a terminal command that prints the file. Cursor's documentation says terminal tools are not governed by `.cursorignore`, so check what you see.
5. Install the hooks (`zn hooks install cursor`), restart Cursor and repeat steps 2 and 4. According to the zn-gate documentation, reads and most shell commands that read the `.env` should now be blocked, and the agent should get a message from the hook instead of the values.
6. Remove the sample folder when you are done. To remove the hooks: `zn hooks uninstall cursor`.

Only your own results count here. If a step behaves differently from what this page says, [tell us](https://usezn.com/contact/) and include your Cursor version.

## Frequently asked questions

**Does `.cursorignore` stop Cursor from reading `.env`?** It blocks the listed files from the agent, Tab, Inline Edit and @ mentions. Cursor's documentation says terminal and MCP tools used by the agent are not governed by it, and that protection is not guaranteed.

**Is `.env` ignored by default in Cursor?** Cursor's documentation lists `.env*` in its default ignore list, together with the files in your `.gitignore`.

**Does zn-gate replace `.cursorignore`?** No. They work at different points. Use both.

**Can zn-gate hide secrets from Cursor's shell output?** No. Cursor does not let hooks change shell or file output; only MCP tool output is scrubbed.

**How do I undo it?** `zn hooks uninstall cursor`.

## Sources

- Cursor, ignore files: <https://cursor.com/docs/context/ignore-files>
- Cursor, hooks: <https://cursor.com/docs/hooks>
- zn-gate, per-agent compatibility: [compat.md](https://github.com/usezn/zn/blob/main/docs/compat.md)
