Overly restrictive .env file blocking prevents reading legitimate files #3245

Closed
opened 2026-02-16 17:39:18 -05:00 by yindo · 6 comments
Owner

Originally created by @Walid-Azur on GitHub (Dec 1, 2025).

Originally assigned to: @rekram1-node on GitHub.

Issue: Overly Restrictive .env File Blocking

Summary

The Read tool blocks access to ANY file containing ".env" in its path, preventing legitimate reads of:

  • Environment configuration files (.env.local, .env.development, .env.production)
  • Source code files with "env" in the path (environment/, config/env/)
  • Template/example files that should be readable (.env.template)

Reproduction

Current Behavior

// Trying to read any file with "env" in path
Read({ filePath: ".env.local" })
// ❌ Error: "The user has blocked you from reading .env.local, DO NOT make further attempts to read it"

Read({ filePath: "src/config/environment.ts" })
// ❌ Error: "The user has blocked you from reading src/config/environment.ts, DO NOT make further attempts to read it"

Read({ filePath: ".env.template" })
// ❌ Error: "The user has blocked you from reading .env.template, DO NOT make further attempts to read it"

Files Currently Blocked

Blocked (shouldn't be):

  • .env.local, .env.development, .env.production
  • .env.template
  • src/environment/config.ts
  • config/env/settings.ts
  • Any path containing "env"

Allowed (whitelist):

  • .env.sample
  • Files ending with .example

Root Cause

Location: packages/opencode/src/tool/read.ts:63-74

const block = iife(() => {
  const whitelist = [".env.sample", ".example"]

  if (whitelist.some((w) => filepath.endsWith(w))) return false
  if (filepath.includes(".env")) return true  // ❌ TOO BROAD

  return false
})

if (block) {
  throw new Error(`The user has blocked you from reading ${filepath}, DO NOT make further attempts to read it`)
}

Problem: The check filepath.includes(".env") blocks:

  1. Any file with "env" anywhere in the path (not just .env files)
  2. All .env variants (.env.local, .env.development, etc.)
  3. Template files that are safe to read

Impact

Development Workflow Issues

  1. Configuration Discovery: Cannot read environment config files to understand app setup
  2. Template Usage: Cannot read .env.template or .env.example files
  3. Source Code: Cannot read legitimate source files with "env" in path
  4. Debugging: Cannot inspect environment configuration when troubleshooting

Security Intent

The blocking was likely intended to:

  • Prevent leaking secrets in .env
  • Protect production credentials

However, it's too aggressive and blocks safe files.

Proposed Solution

Recommended Fix: Basename-Based Blocking

Make the blocking more precise by checking only the filename, not the full path:

const block = iife(() => {
  const whitelist = [
    ".env.sample",
    ".env.example",
    ".example",
    ".env.template",
    ".env.schema"
  ]

  if (whitelist.some((w) => filepath.endsWith(w))) return false

  // Only block files that ARE actual .env files (basename check)
  const basename = path.basename(filepath)
  if (basename.startsWith(".env")) return true

  return false
})

if (block) {
  throw new Error(`The user has blocked you from reading ${filepath}, DO NOT make further attempts to read it`)
}

Alternative: Pattern-Based Whitelist

More explicit pattern matching:

const block = iife(() => {
  const basename = path.basename(filepath)

  // Whitelist: Safe template/example files
  const safePatterns = [
    /\.env\.sample$/,
    /\.env\.example$/,
    /\.env\.template$/,
    /\.env\.schema$/,
    /\.example$/
  ]

  if (safePatterns.some(pattern => pattern.test(filepath))) {
    return false
  }

  // Block: Actual .env files with potential secrets
  const blockPatterns = [
    /^\.env$/,                    // .env
    /^\.env\.local$/,             // .env.local
    /^\.env\.development$/,       // .env.development
    /^\.env\.production$/,        // .env.production
    /^\.env\.staging$/,           // .env.staging
    /^\.env\.test$/,              // .env.test
    /^\.env\.[a-z]+\.local$/      // .env.*.local
  ]

  return blockPatterns.some(pattern => pattern.test(basename))
})

Comparison Table

File Path Current Behavior After Fix
.env Blocked Blocked (correct)
.env.local Blocked Blocked (correct)
.env.production Blocked Blocked (correct)
.env.sample Allowed Allowed
.env.example Allowed Allowed
.env.template Blocked Allowed (fix)
src/environment.ts Blocked Allowed (fix)
config/env/settings.ts Blocked Allowed (fix)
.example Allowed Allowed

Testing

To verify fix:

// Test 1: Block actual .env files
Read({ filePath: ".env" })
// Should throw: blocked

Read({ filePath: ".env.local" })
// Should throw: blocked

// Test 2: Allow template files
Read({ filePath: ".env.template" })
// Should succeed

Read({ filePath: ".env.example" })
// Should succeed

// Test 3: Allow source files with "env" in path
Read({ filePath: "src/config/environment.ts" })
// Should succeed

Read({ filePath: "utils/envParser.ts" })
// Should succeed

Security Considerations

The fix maintains security by:

  • Still blocking .env and variants (.env.local, .env.production, etc.)
  • Preventing accidental secret leakage
  • Allowing safe template/example files
  • Not blocking legitimate source code

Additional Context

  • Security Goal: Prevent reading files with actual secrets
  • User Experience: Allow reading configuration templates and source code
  • Best Practice: Use .env.example or .env.template for documentation
  • Related Code: packages/opencode/src/tool/read.ts

References

Originally created by @Walid-Azur on GitHub (Dec 1, 2025). Originally assigned to: @rekram1-node on GitHub. # Issue: Overly Restrictive .env File Blocking ## Summary The Read tool blocks access to ANY file containing ".env" in its path, preventing legitimate reads of: - Environment configuration files (`.env.local`, `.env.development`, `.env.production`) - Source code files with "env" in the path (`environment/`, `config/env/`) - Template/example files that should be readable (`.env.template`) ## Reproduction ### Current Behavior ```typescript // Trying to read any file with "env" in path Read({ filePath: ".env.local" }) // ❌ Error: "The user has blocked you from reading .env.local, DO NOT make further attempts to read it" Read({ filePath: "src/config/environment.ts" }) // ❌ Error: "The user has blocked you from reading src/config/environment.ts, DO NOT make further attempts to read it" Read({ filePath: ".env.template" }) // ❌ Error: "The user has blocked you from reading .env.template, DO NOT make further attempts to read it" ``` ### Files Currently Blocked ❌ **Blocked (shouldn't be)**: - `.env.local`, `.env.development`, `.env.production` - `.env.template` - `src/environment/config.ts` - `config/env/settings.ts` - Any path containing "env" ✅ **Allowed (whitelist)**: - `.env.sample` - Files ending with `.example` ## Root Cause **Location**: `packages/opencode/src/tool/read.ts:63-74` ```typescript const block = iife(() => { const whitelist = [".env.sample", ".example"] if (whitelist.some((w) => filepath.endsWith(w))) return false if (filepath.includes(".env")) return true // ❌ TOO BROAD return false }) if (block) { throw new Error(`The user has blocked you from reading ${filepath}, DO NOT make further attempts to read it`) } ``` **Problem**: The check `filepath.includes(".env")` blocks: 1. **Any file with "env" anywhere in the path** (not just .env files) 2. **All .env variants** (`.env.local`, `.env.development`, etc.) 3. **Template files** that are safe to read ## Impact ### Development Workflow Issues 1. **Configuration Discovery**: Cannot read environment config files to understand app setup 2. **Template Usage**: Cannot read `.env.template` or `.env.example` files 3. **Source Code**: Cannot read legitimate source files with "env" in path 4. **Debugging**: Cannot inspect environment configuration when troubleshooting ### Security Intent The blocking was likely intended to: - ✅ Prevent leaking secrets in `.env` - ✅ Protect production credentials However, it's too aggressive and blocks safe files. ## Proposed Solution ### Recommended Fix: Basename-Based Blocking Make the blocking more precise by checking only the filename, not the full path: ```typescript const block = iife(() => { const whitelist = [ ".env.sample", ".env.example", ".example", ".env.template", ".env.schema" ] if (whitelist.some((w) => filepath.endsWith(w))) return false // Only block files that ARE actual .env files (basename check) const basename = path.basename(filepath) if (basename.startsWith(".env")) return true return false }) if (block) { throw new Error(`The user has blocked you from reading ${filepath}, DO NOT make further attempts to read it`) } ``` ### Alternative: Pattern-Based Whitelist More explicit pattern matching: ```typescript const block = iife(() => { const basename = path.basename(filepath) // Whitelist: Safe template/example files const safePatterns = [ /\.env\.sample$/, /\.env\.example$/, /\.env\.template$/, /\.env\.schema$/, /\.example$/ ] if (safePatterns.some(pattern => pattern.test(filepath))) { return false } // Block: Actual .env files with potential secrets const blockPatterns = [ /^\.env$/, // .env /^\.env\.local$/, // .env.local /^\.env\.development$/, // .env.development /^\.env\.production$/, // .env.production /^\.env\.staging$/, // .env.staging /^\.env\.test$/, // .env.test /^\.env\.[a-z]+\.local$/ // .env.*.local ] return blockPatterns.some(pattern => pattern.test(basename)) }) ``` ## Comparison Table | File Path | Current Behavior | After Fix | |-----------|-----------------|-----------| | `.env` | ❌ Blocked | ❌ Blocked (correct) | | `.env.local` | ❌ Blocked | ❌ Blocked (correct) | | `.env.production` | ❌ Blocked | ❌ Blocked (correct) | | `.env.sample` | ✅ Allowed | ✅ Allowed | | `.env.example` | ✅ Allowed | ✅ Allowed | | `.env.template` | ❌ Blocked | ✅ Allowed (fix) | | `src/environment.ts` | ❌ Blocked | ✅ Allowed (fix) | | `config/env/settings.ts` | ❌ Blocked | ✅ Allowed (fix) | | `.example` | ✅ Allowed | ✅ Allowed | ## Testing To verify fix: ```typescript // Test 1: Block actual .env files Read({ filePath: ".env" }) // Should throw: blocked Read({ filePath: ".env.local" }) // Should throw: blocked // Test 2: Allow template files Read({ filePath: ".env.template" }) // Should succeed Read({ filePath: ".env.example" }) // Should succeed // Test 3: Allow source files with "env" in path Read({ filePath: "src/config/environment.ts" }) // Should succeed Read({ filePath: "utils/envParser.ts" }) // Should succeed ``` ## Security Considerations The fix maintains security by: - ✅ Still blocking `.env` and variants (`.env.local`, `.env.production`, etc.) - ✅ Preventing accidental secret leakage - ✅ Allowing safe template/example files - ✅ Not blocking legitimate source code ## Additional Context - **Security Goal**: Prevent reading files with actual secrets - **User Experience**: Allow reading configuration templates and source code - **Best Practice**: Use `.env.example` or `.env.template` for documentation - **Related Code**: `packages/opencode/src/tool/read.ts` ## References - Twelve-Factor App: https://12factor.net/config - dotenv best practices: https://github.com/motdotla/dotenv#should-i-commit-my-env-file
yindo closed this issue 2026-02-16 17:39:18 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Dec 1, 2025):

This issue might be a duplicate of or closely related to existing issues. Please check:

  • #4961: Feature Request: Zero-Trust Architecture for Environment Variable Security - Proposes implementing client-side secret detection and placeholder replacement to prevent actual secrets from being transmitted to LLM providers. This addresses the same underlying security/usability concern but from a different angle (content transformation vs file blocking).

  • #539 (CLOSED): [SECURITY] allow ignoring files to prevent secrets being leaked from .env to LLM - The original security concern that led to the current blocking mechanism. Understanding this closed issue's resolution may provide context for refining the approach.

  • #4667: Limiting access for tools in a safer way - Proposes a broader security context model for tools. May be related if file access restrictions are being reconsidered as part of a larger security framework.

Feel free to ignore if your specific case differs from these, but they may provide useful context for the .env file handling discussion.

@github-actions[bot] commented on GitHub (Dec 1, 2025): This issue might be a duplicate of or closely related to existing issues. Please check: - #4961: Feature Request: Zero-Trust Architecture for Environment Variable Security - Proposes implementing client-side secret detection and placeholder replacement to prevent actual secrets from being transmitted to LLM providers. This addresses the same underlying security/usability concern but from a different angle (content transformation vs file blocking). - #539 (CLOSED): [SECURITY] allow ignoring files to prevent secrets being leaked from .env to LLM - The original security concern that led to the current blocking mechanism. Understanding this closed issue's resolution may provide context for refining the approach. - #4667: Limiting access for tools in a safer way - Proposes a broader security context model for tools. May be related if file access restrictions are being reconsidered as part of a larger security framework. Feel free to ignore if your specific case differs from these, but they may provide useful context for the .env file handling discussion.
Author
Owner

@nikvdp commented on GitHub (Dec 10, 2025):

+1, Blocking .env files is great as a security-minded default, but users need control over what gets blacklisted when. And saying that the user requested this in the error message is downright misleading!

The current approach also blocks other legitimate use cases, for example opencode is now incapable of editing direnv configs cause they go in .envrc which trips the substring match and gets blocked by this code. I'm having to dust off claude code just to edit my direnv config 😨!

@nikvdp commented on GitHub (Dec 10, 2025): +1, Blocking `.env` files is great as a security-minded default, but users need control over what gets blacklisted when. And saying that the user requested this in the error message is downright misleading! The current approach also blocks other legitimate use cases, for example opencode is now incapable of editing direnv configs cause they go in `.envrc` which trips the substring match and gets blocked by this code. I'm having to dust off claude code just to edit my direnv config 😨!
Author
Owner

@rekram1-node commented on GitHub (Dec 10, 2025):

Yeah ill make it better v soon

@rekram1-node commented on GitHub (Dec 10, 2025): Yeah ill make it better v soon
Author
Owner

@Act0r1 commented on GitHub (Dec 14, 2025):

hi guys, i still searching here for config, i don't find any config, only permission from official documentation, that globally restrict AI from reading any files with some type of patterns, like claude code have, here no solution right now for this right ?

@Act0r1 commented on GitHub (Dec 14, 2025): hi guys, i still searching here for config, i don't find any config, only permission from official documentation, that globally restrict AI from reading any files with some type of patterns, like claude code have, here no solution right now for this right ?
Author
Owner

@khoa5935 commented on GitHub (Dec 19, 2025):

holy, all laravel projects got messy due to this .env blocking...

@khoa5935 commented on GitHub (Dec 19, 2025): holy, all laravel projects got messy due to this .env blocking...
Author
Owner

@edxeth commented on GitHub (Jan 12, 2026):

The solution is very straightforward, simply give read permissions to OpenCode in opencode.json:

  		"read": {
			"*.env*": "allow",
			"*": "allow"
		},

Be aware of the risks this carries.

@edxeth commented on GitHub (Jan 12, 2026): The solution is very straightforward, simply give read permissions to OpenCode in `opencode.json`: ```json "read": { "*.env*": "allow", "*": "allow" }, ``` Be aware of the risks this carries.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#3245