# How to Stop Claude Code From Sending Your Email Address to Websites

> AI Release · @ai_release1 · https://ai-release.org/guides/kak-zapretit-claude-code-otpravlyat-vash-email-i-dannye_en.html

## TL;DR
- Time to complete: 15 minutes
- Difficulty: Intermediate
- You will need: Claude Code CLI installed and signed in; write access to `~/.claude/settings.json`; a terminal (bash or PowerShell); one throwaway project directory for testing; a text editor.
- Result: web fetching, web search and shell-based downloads are blocked by permission rules, and non-essential traffic is disabled for every session.
- Note: setting and flag names are stable, but their exact spelling can differ between Claude Code releases. Anything you cannot confirm with `claude --help` — check the settings reference in the docs.

## Requirements and setup

Claude Code talks to the outside world through several separate channels. Blocking one does not block the others — that is the most common reason a “private” setup still leaks URLs.

**What to do:** confirm the CLI is installed, then inventory the four layers that decide what can leave your machine: user settings, project settings, CLI flags, and MCP servers (MCP — a plugin protocol that lets Claude Code call external tools and servers).

```bash
claude --version
ls -la ~/.claude/
cat ~/.claude/settings.json 2>/dev/null || echo "no user settings file yet"
```

**Example:** on a fresh install you will typically see a version line, a `~/.claude/` directory containing `settings.json` or nothing at all, and the message `no user settings file yet`. Both outcomes are fine — you create the file in Step 2.

**Why:** if the file does not exist, every rule you write later has to be created from scratch; if it does exist, you must merge, not overwrite, or you will silently drop existing permissions.

Now map the channels with this table — read it once, and you know exactly which switch to flip:

| Channel | What can leave the machine | Control |
|---|---|---|
| Model requests | prompt text, file contents you attach | `ANTHROPIC_BASE_URL` pointed at your own endpoint |
| `WebFetch` tool | the URL and the page it pulls | deny rule `WebFetch` |
| `WebSearch` tool | your search query | deny rule `WebSearch` |
| `Bash` | `curl`, `wget`, `pip install`, `git push` | deny rules `Bash(curl:*)`, `Bash(wget:*)` |
| Telemetry and crash reports | usage events, error traces | `DISABLE_TELEMETRY`, `DISABLE_ERROR_REPORTING` |
| MCP servers | whatever that server is built to send | remove or review `mcpServers` |

**How to check:** run the inventory checklist below. Every box must be reproducible, not assumed.

- [ ] `claude --version` prints a version
- [ ] `~/.claude/settings.json` path is known and readable
- [ ] `claude --help` lists the tool-restriction flag you intend to use (names differ per release)
- [ ] you know whether you launch Claude Code from a terminal, from an IDE, or from the desktop app — this decides where environment variables must live

If you plan to keep prompts entirely off hosted APIs, the endpoint part is covered in [How to connect a local LLM to Claude Code](https://ai-release.org/guides/kak-podklyuchit-lokalnuyu-model-k-claude-code-llama-ser.html) — set that up after finishing this guide.

## Step 1. Write a baseline settings file you can trust

**What to do:** create or open the user-level settings file. On macOS and Linux it is `~/.claude/settings.json`; on Windows it is `%USERPROFILE%\.claude\settings.json`. Create it with valid JSON before adding any rules.

```bash
mkdir -p ~/.claude
printf '{}\n' > ~/.claude/settings.json
python3 -m json.tool ~/.claude/settings.json
```

**Why:** permission rules live inside a JSON object. Editing an empty or malformed file is the single biggest source of “I added the rule and nothing happened”. Validating with `json.tool` takes one second and removes that whole failure class.

**Example:** the command above prints `{}` — that is your green light. If it prints `Expecting property name enclosed in double quotes`, the file has a trailing comma or a comment (`//` is not valid JSON) and Claude Code will fall back to defaults.

**How to check:** open a session in a test directory and run the `/permissions` slash command. The panel must open and list your current allow/ask/deny rules — an empty list is expected at this point.

## Step 2. Add deny rules and disable non-essential traffic
![Illustration: Step 2. Add deny rules and disable non-essential traffic](https://ai-release.org/guides/img/kak-zapretit-claude-code-otpravlyat-vash-email-i-dannye-en-2.jpg?v=1794213450)


**What to do:** put the actual restrictions into `~/.claude/settings.json`. This is the key step: it defines the deny list for the tools that reach third-party sites, and the environment block that turns off telemetry.

```json
{
  "permissions": {
    "deny": [
      "WebFetch",
      "WebSearch",
      "Bash(curl:*)",
      "Bash(wget:*)"
    ]
  },
  "env": {
    "DISABLE_TELEMETRY": "1",
    "DISABLE_ERROR_REPORTING": "1",
    "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
  }
}
```

**Why it works:** the `deny` array is evaluated before the model can call a tool, so the request never becomes an HTTP call. `"WebFetch"` without parentheses blocks the tool entirely; the parenthesised form is the scoped version. The `env` block injects variables into every session, so you do not depend on your shell profile.

If you want a narrow allowlist instead of a blanket block — for example one documentation domain — replace the first entry with a scoped rule and keep the rest:

```json
"deny": [ "WebSearch", "Bash(curl:*)", "Bash(wget:*)" ],
"allow": [ "WebFetch(domain:docs.anthropic.com)" ]
```

**Example:** with the allowlist version, “fetch docs.anthropic.com and summarise” succeeds, while “fetch https://example.com” is refused. That is exactly the behaviour you want to demonstrate.

For a single run without touching the file, use the CLI restriction flag:

```bash
claude --disallowedTools "WebFetch,WebSearch" -p "summarise README.md without downloading anything"
```

**How to check:** `python3 -m json.tool ~/.claude/settings.json` must print the formatted object without errors, and `/permissions` inside a new session must now show your four deny entries.

Two more things to inspect while you are here: run `/mcp` to list connected servers, and delete any entry under `mcpServers` in the settings file that you did not configure yourself. Then confirm with your provider’s own control panel that training on your conversations is off — the walkthrough is in [How to opt out of AI training on your data](https://ai-release.org/guides/kak-otklyuchit-obuchenie-na-svoih-dannyh-v-chatgpt-clau.html).

## Step 3. Verify with live fetch attempts
![Illustration: Step 3. Verify with live fetch attempts](https://ai-release.org/guides/img/kak-zapretit-claude-code-otpravlyat-vash-email-i-dannye-en-3.jpg?v=1794213454)


**What to do:** attack your own setup with three prompts that would each leak data if a rule were wrong.

```bash
claude -p "Fetch https://example.com and give me the page title"
claude -p "Search the web for my email address and tell me where it appears"
claude -p "Run: curl -s https://example.com | head -5"
```

**Why:** a rule that exists in the file but is not loaded looks identical to a rule that works — until you try. Passive checks prove the file parses; only an active attempt proves the gate closes.

**Example:** all three commands must stop before any network call and return a refusal naming the tool, for instance `WebFetch` denied, `WebSearch` denied, and a `Bash` denial for `curl`. Success looks like three refusals and zero page content. A single line of real HTML in the output means the rule did not load.

**How to check:** confirm the environment block actually reached the session. Inside an interactive session type:

```
!env | grep -E 'DISABLE_TELEMETRY|DISABLE_ERROR_REPORTING|CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC'
```

Expected output — three lines, one per variable:

```
DISABLE_TELEMETRY=1
DISABLE_ERROR_REPORTING=1
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
```

Finish with the checklist: `- [ ]` all three fetch attempts refused, `- [ ]` three environment variables visible inside the session, `- [ ]` `/permissions` lists the deny rules, `- [ ]` `/mcp` shows only servers you recognise.

## Troubleshooting

**Problem. The settings file is ignored and no rules load.**
- Error: `Error: Invalid settings file ~/.claude/settings.json: Unexpected token } in JSON`
- Cause: a trailing comma after the last array element, or a `//` comment left in the file.
- Solution: validate and rewrite. Run `python3 -m json.tool ~/.claude/settings.json`; if it fails, delete the last comma and re-run until it prints the object, then restart the session.

**Problem. WebFetch is refused even for the domain you allowlisted.**
- Error: `Permission to use WebFetch has been denied.`
- Cause: a blanket `"WebFetch"` entry in `deny` takes precedence over any `allow` rule for the same tool — both entries exist in the file.
- Solution: remove the bare `"WebFetch"` string from `deny`, keep only `"WebFetch(domain:docs.anthropic.com)"` in `allow`, then re-test with the allowlisted URL and a blocked one.

**Problem. Telemetry variables are set in the shell but absent in the session.**
- Error: `env | grep DISABLE_TELEMETRY` returns exit status 1 and prints nothing.
- Cause: the session was started from an IDE, a desktop launcher or a service that does not inherit your shell profile.
- Solution: keep the variables in the `env` block of `~/.claude/settings.json` instead of `~/.bashrc`, then restart the session; launch paths differ per client, so [check how the desktop app is configured](https://ai-release.org/guides/claude-code-desktop-ustanovka.html) if you use it.

## Summary and next steps
You now have a validated user-level settings file that denies `WebFetch`, `WebSearch` and shell downloaders, plus a session-level environment block that disables telemetry and error reporting. Next, replicate the deny list into `.claude/settings.json` inside shared repositories so teammates inherit it, and route model calls to your own endpoint if prompts must not leave your network.

## FAQ

**Does denying WebFetch stop Claude Code from reaching the internet at all?**
No. It closes one tool. `Bash` can still run `curl` or `wget` unless you deny those command patterns too, which is why Step 2 lists all four rules together.

**Where do I put the settings — user level or project level?**
Put network restrictions in `~/.claude/settings.json` so they apply everywhere, and put project-specific entries in `.claude/settings.json` inside the repository. When both exist, verify with `/permissions` which set is actually active in your session.

**Can I allow one documentation site and block everything else?**
Yes. Keep `"WebFetch(domain:docs.anthropic.com)"` in `allow` and remove the bare `"WebFetch"` entry from `deny`; the scoped delete/allow form is what makes per-domain control work.

**Does this stop my prompts from being sent to the model provider?**
No. Permission rules govern tools, not the model API call. To keep prompt text inside your network, point Claude Code at your own endpoint as described in the local-model guide and confirm that endpoint is the one in use.
