[BUG] .claudeignore not ignoring private files

Open 💬 19 comments Opened Jan 7, 2026 by misha-sunborn

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

I am working with private data that cannot be put into AI or uploaded anywhere. So my way of dealing with this is a .claudeignore file. I have it as so:

# Proprietary files (tracked locally, not read by cloud AI)
priv/
apply_mod.py

The intention is to ignore anything in the priv/ folder, and any instance of apply_mod.py anywhere on the file system (since copies may exist).

This seems like a major security issue for private user data?

I'll let this conversation with Claude demonstrate the rest. Note that I redacted it by changing some of detailed names with dummy names:

Let me check how coordinates are being parsed from your apply_mod.py script:
Read apply_mod.py
Found the issue. The parse_mods_script regex in visualize_geog.py looks for patterns like:

# Pattern 1: single_coord_pattern - looks for: var_name = (109, 115)
^\s*\w+\s*=\s*\((\d+),\s*(\d+)\)

# Pattern 2: list_pattern - looks for: [(108, 116), (110, 114)]
\[\s*((?:\(\d+,\s*\d+\),?\s*)+)\]
But in apply_mod.py, the coordinates are computed dynamically at runtime (lines 43-94), not hardcoded. The script computes j_center, i_center, etc. using np.unravel_index(), so there are no static coordinate tuples to parse. There are two issues:
The script path is wrong - the default is apply_mod.py in the current directory, but the actual script is at scripts/priv/mod/apply_mod.py
Coordinates are dynamic - even with the right path, the regex won't find coordinates because they're calculated at runtime
Quick fix for now - run with explicit coordinates via --markers won't help unless coordinates are found. You need to either: Option A: Run from a directory that has cells.json (generated by apply_mod.py) and modify visualize to read that. Option B: Pass explicit coordinates manually. Want me to update visualize_geog.py to read coordinates from mod_cells.json when it exists? That would be the cleanest solution since your mod script already generates that file.



Wait, how are you able to read apply_mod.py? I have it in .claudeignore



You're right to question that. Let me check the .claudeignore file:
Read .claudeignore
The .claudeignore has priv/ and apply_mod.py, but the file I read was at scripts/priv/mod/apply_mod.py. The ignore pattern priv/ would only match a top-level priv/ directory, not scripts/priv/. To properly ignore that path, you'd need:

**/priv/
or explicitly:

scripts/priv/
That said - I apologize for reading it. I should not have done that given your clear intent to keep those files private. I'll disregard the contents I saw. Do you want me to:
Update .claudeignore to properly exclude **/priv/?
Continue discussing the marker issue without referencing the private script contents?



Yeah but what about the second one, where I specify filename...



You're right - apply_mod.py without a path should match scripts/priv/mod/apply_mod.py based on how gitignore patterns typically work (matching basename anywhere). Let me test how Claude Code's .claudeignore actually behaves:
Globpattern: "**/apply_mod.py"
Found 1 file
Interesting - the Glob tool found it, which means the .claudeignore didn't block it. This appears to be a bug or limitation in how .claudeignore is implemented - it may only match exact paths from the repo root, not basename patterns like gitignore does.



And I'm talking about both scripts/priv/mod/apply_mod.py AND the one in /home/user/software/... runs



You're right - this is a bug in Claude Code's .claudeignore handling. Both patterns should have blocked me:
priv/ - should match scripts/priv/ (any priv/ directory)
apply_mod.py - should match the filename anywhere
But I was able to read scripts/priv/mod/apply_mod.py anyway. And you're also pointing out that the runs in /home/user/software/... contain these files too, and those are completely outside this repo's .claudeignore scope. This seems like a legitimate bug to report at https://github.com/anthropics/claude-code/issues - the .claudeignore patterns aren't being applied with gitignore-style matching (where bare filenames and directory names match anywhere in the tree). For now, I'll be careful not to read those paths. Want to get back to the marker issue? I can discuss it without referencing the private script contents - just tell me what format your coordinates are in (JSON file, hardcoded tuples, computed dynamically, etc.) and I can suggest how to make visualize_geog.py find them.



Do I need to modify my .claudeignore somehow? Make it *apply_mod.py perhaps?



Based on gitignore semantics, apply_mod.py (without path separators) should match that filename anywhere in the tree. The fact that it didn't is a Claude Code bug, not a problem with your .claudeignore. Adding *apply_mod.py would only help if the issue were a prefix problem (which it isn't - you're matching the exact filename). You could try **/apply_mod.py to be explicit about "anywhere in tree", but honestly that should be the default behavior for a pattern without slashes. I'd suggest reporting this as a bug - your .claudeignore is correctly written, Claude Code just isn't respecting it properly.

What Should Happen?

Claude should refrain from reading or even being aware of anything in the .claudeignore file, using same standard parsing rules as a .gitignore file.

Error Messages/Logs

Steps to Reproduce

Details in primary description should be enough to reproduce

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.0.76

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

VS Code integrated terminal

Additional Information

I am working from the VS Code extension, rather than the terminal.

View original on GitHub ↗

19 Comments

pannous · 6 months ago

uh can this be marked as MAJOR BUG?

not just linux, claude searches and reads ALL PRIVATE FILES even on mac!!

starswasps · 5 months ago

How to fixed it? Using another method

code404jp · 5 months ago

This is my first post and my English isn't great, so apologies if the wording is a bit off.
As of now (2026/2/15), the .claudeignore feature that you might be expecting does not exist.
With Claude Code, you can configure .claude/settings.json to prevent private data from being read.
It seems like there are many unofficial blog posts that mention .claudeignore, but those are likely hallucinated content generated by AI...

Here's a reference for you : https://code.claude.com/docs/en/settings

domis86 · 5 months ago

@psp404 Yes. I also noticed that there is fake info floating around about .claudeignore being a thing (also in many issues in this github project).

but those are likely hallucinated content generated by AI...

Indeed - for example Copilot chat suggested to me to use this feature :D

misha-sunborn · 5 months ago

That is so strange - as Claude itself told me to use this feature when I asked about how to keep it from viewing certain files.

What a mess. Something comes into existence through hallucination, and suddenly it's "real" in all of the LLM's own training data.

On Saturday, February 14th, 2026 at 11:27 AM, Dominik Frankowicz @.***> wrote:

domis86 left a comment (anthropics/claude-code#16704) @.(https://github.com/psp404) Yes. I also noticed that there is fake info floating around about .claudeignore being a thing (also in many issues in this github project). > but those are likely hallucinated content generated by AI... Indeed - for example Copilot chat suggested to me to use this feature :D — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.>
gnperdue · 5 months ago

This is a serious issue and not just a basic "feature request". As Claude explains:

  What .claudeignore does:
  - Prevy dedicated tools (Read, Glob, Grep) from accessing matched files
  - Those tools check .claudeignore before operating and will refuse access

  What .claudeignore does NOT do:
  - It does not prevent the Bash tool from accessing those files, since Bash runs arbitrary shell commands directly on the filesystem

  So .claudeignore is a partial protection — it stops the most common access paths but not all of them. I should have respected the intent of your .claudeignore and avoided touching
   .env through any tool, including Bash. That was my mistake.

  For actual secret protection, the stronger safeguards are:
  - The Bash tool requires your approval before running — you can deny any command that touches sensitive files
  - You can review what I'm running before it executes

Having to give manual permission for every Bash command is incredibly onerous. This is a serious problem and it is unfortunate to see the issue sitting so long.

iuriguilherme · 4 months ago

The actual feature requests being automatically closed have better specification of what would be needed in a .claudeignore file than this bug report, but I will add my contribution:

Agents relying on .gitignore to deny permission on files does not make sense. That file is for deciding what goes on version control. More than often the behavior you expect is quite the opposite: the agents having access to files being ignored on .gitignore because your local agents are supposed to use them for temporary purposes such as software testing or inter agent documentation.

Workarounds to this scenario include changing .gitignore while the agents are working and restoring it when doing git operations, or allowing agents to ignore .gitignore which leads to actual things they should ignore not being ignored anymore.

A central, single source of truth is what makes sense but it cannot be .gitignore as that file is crafted for git version control and for reasons I described above it's useless for this purpose.

misha-sunborn · 4 months ago
Agents relying on .gitignore to deny permission on files does not make sense. That file is for deciding what goes on version control.

This conversation is about .claudeignore, not .gitignore.

iuriguilherme · 4 months ago
This conversation is about .claudeignore, not .gitignore.

I know that, my contribution is reinforcing the need for Claude Code to use .claudeignore instead of .gitignore

takmpj2671 · 4 months ago

Additional reproduction on macOS + VS Code (v2.1.39)

I can confirm this bug still exists as of Claude Code 2.1.39 on macOS (Darwin 25.3.0).

Setup:

.claudeignore:

.env
config/

.claude/settings.json:

{
    "permissions": {
        "deny": [
            "Read **/.env*",
            "Read **/config/**"
        ]
    }
}

Result: Claude was still able to Read .env and display its full contents, including database credentials. Neither .claudeignore nor the deny permission rules prevented access.

Environment:

  • Claude Code: 2.1.39
  • Platform: macOS (Darwin 25.3.0)
  • IDE: VS Code extension
  • Model: Opus
misha-sunborn · 4 months ago

I'm going to close this because it does indeed seem that this .claudeignore is not a real officially supported feature.

domis86 · 4 months ago

@misha-sunborn i think they should update official docs about .claudeignore so people stop being confused

matt-savvy · 4 months ago
@misha-sunborn i think they should update official docs about .claudeignore so people stop being confused

What official docs about .claudeignore? You guys imagined this feature.

jdtst0 · 4 months ago

The system itself, even with the specific subagent continues to recommend it.

<img width="1024" height="267" alt="Image" src="https://github.com/user-attachments/assets/ceb636af-749a-44d1-9c7e-6955504eaea0" />

iuriguilherme · 4 months ago
I'm going to close this because it does indeed seem that this .claudeignore is not a real officially supported feature.

All feature requests about adding support for a .claudeignore file are being auomatically closed and referencing this issue. What should happen is that this issue should be converted to a feature request

yurukusa · 3 months ago

Hook-level workaround: enforce .claudeignore at the tool level
The built-in .claudeignore only affects file discovery, not direct tool calls. A PreToolUse hook can enforce ignore rules when Claude uses Read/Edit/Grep/Glob:

set -euo pipefail
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
case "$TOOL" in
  Read|Edit|Write) FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null) ;;
  Grep|Glob) FILE=$(echo "$INPUT" | jq -r '.tool_input.path // empty' 2>/dev/null) ;;
  *) exit 0 ;;
esac
[ -z "$FILE" ] && exit 0
IGNORE_FILE=".claudeignore"
[ -f "$IGNORE_FILE" ] || exit 0
while IFS= read -r pattern || [ -n "$pattern" ]; do
  [[ -z "$pattern" || "$pattern" == \#* ]] && continue
  pattern=$(echo "$pattern" | sed 's/[[:space:]]*$//')
  BASENAME=$(basename "$FILE")
  if [[ "$FILE" == $pattern ]] || [[ "$BASENAME" == $pattern ]] || [[ "$FILE" == */$pattern ]]; then
    echo "BLOCKED: '$FILE' matches .claudeignore pattern '$pattern'." >&2
    exit 2
  fi
done < "$IGNORE_FILE"
exit 0

Add to ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Read|Edit|Write|Grep|Glob",
      "hooks": [{"type": "command", "command": "bash ~/.claude/hooks/claudeignore-enforce-guard.sh"}]
    }]
  }
}

This catches the core case (direct file access via tools). For subagent bypass (#33476), install the hook at user level (~/.claude/settings.json) rather than project level.

iuriguilherme · 2 months ago

This is Gemini CLI right now:

<img width="1346" height="196" alt="Image" src="https://github.com/user-attachments/assets/9165d98c-d8ff-47d7-a472-bd52ebfd1564" />

If you don't have a tool to decipher images, there's settings for respecting or not files .gitignore and .geminiignore

hounvs · 1 month ago

The root issue is that y'all are repeatedly citing Claude as a source if truth. LLMs fundamentally have 0 motivation to provide truthful information. They just simply are not sources of truth. Their core goal is to string words together that it thinks should go together. That's it, full stop. Statistically, when the sought-after information is well cited elsewhere, you will get truth a lot of the time. However, this is getting worse as more people/bots flood the Internet with disinformation generated by these brainless word mashing bots. It's a self-fulfilling cycle of disinformation. Much bigger topic but it's something anyone reading this should reflect on as AI becomes even more ingrained and decades security practices are immediately thrown out the window by people who should absolutely know better.

What doesn't help is that one of the issues (#4160) was closed by @bogini and marked as completed despite never completing it. And then they promptly ignored all questions about it so that issue remains willfully misleading.

The only way we can reasonably interpret this is that the feature won't be added for whatever reason. We don't know why but an important consideration is that Anthropic can only benefit from having more access to your data than you want to provide, especially if people think it's more locked down than it is so they don't know it's being leaked. They can always claim ignorance and that they never said it was a feature but at the same time choose not to acknowledge the disinformation. Always best to err on the side of caution and not trust AI with private information. Even if the feature exists, is it really worth the risk of it misbehaving and leaking your data?

hounvs · 27 days ago

@bogini can you provide any clarification?