Corrective Action: CRLF Line Endings Causing Silent Token Loading Failures Across Infrastructure
Date: March 8, 2026 Category: Data Format Mismatch + Verification Failure Impact: Token loading failures across every session, cascading into credential leakage into settings.local.json, MCP tool unavailability, and wasted session time Resolution Time: ~90 minutes from diagnosis to fix (but the problem existed since system creation)
Incident
What Happened
Every .env file created on the Windows/WSL system had CRLF (\r\n) line endings. Bash source .env silently fails to parse CRLF files — it reads the \r as part of the value, making every token invalid. This caused cascading failures: HubSpot API calls failed with "invalid token," MCP servers couldn't authenticate, and Claude Code sessions repeatedly couldn't locate working credentials.
The secondary effect was more insidious: when Claude couldn't find tokens through normal channels, it hardcoded them inline in bash commands (e.g., HUBSPOT_ACCESS_TOKEN=pat-na1-... node script.js). Claude Code then saved these approved commands — credentials included — as permanent permission rules in settings.local.json. Three leaked credentials were found.
Timeline
| Time | Event |
|---|---|
| System creation (Feb 2026) | .env files created on Windows — all have CRLF line endings |
| Every session since | source .env silently fails; tokens appear loaded but contain trailing \r |
| Every session since | Claude falls back to hardcoding tokens inline in bash commands |
| Unknown dates (3 incidents) | Claude Code saves inline-token bash commands as permanent permission rules |
| Mar 8 ~10:30 AM CT | /weekly-plan session: token loading fails, HubSpot MCP unavailable |
| Mar 8 ~11:00 AM CT | Root cause identified: CRLF in .env files |
| Mar 8 ~11:30 AM CT | 29 .env files converted to LF; .editorconfig created; 3 leaked credentials scrubbed from settings.local.json |
| Mar 8 ~12:00 PM CT | Fix committed and pushed (.editorconfig — .env files are gitignored) |
Root Cause
The failure mechanism has three layers:
Layer 1 — File Creation: Chris uses Windows (D: drive mounted as /mnt/d in WSL). Text editors on Windows create files with \r\n (CRLF) line endings by default. Every .env file in the system — monorepo root, per-client directories, and the D drive root — had CRLF endings.
Layer 2 — Silent Parse Failure: Bash source .env on a CRLF file reads TOKEN=value\r instead of TOKEN=value. The trailing \r is invisible but makes the token invalid for API calls. There is no error message. The variable appears to be set. echo $TOKEN shows the value. But every HTTP request using it gets a 401.
Layer 3 — Cascading Credential Leakage: When normal token loading fails, Claude Code adapts by inlining credentials directly in bash commands: HUBSPOT_ACCESS_TOKEN=pat-na1-xxx node script.js. When the user approves this command, Claude Code saves it as a permission rule in settings.local.json — credentials and all. This creates a permanent, plaintext record of every token that was ever hardcoded as a workaround.
Category: Data Format Mismatch + Verification Failure
This is a cross-platform data format issue that manifests as a silent failure. The .gitattributes file already enforced LF for tracked files, but .env files are gitignored — they were never normalized.
The verification failure component: no session startup check ever validated that loaded tokens were actually functional. Token loading was assumed to succeed if the file existed.
Fix Applied
Immediate Resolution
- Converted all 29
.envand.env.examplefiles from CRLF to LF usingsed -i 's/\r$//' - Created
.editorconfigat monorepo root to prevent future CRLF contamination - Scrubbed 3 leaked credentials from
settings.local.json(replaced exact tokens with wildcard patterns) - Removed 1 malformed permission entry from
settings.local.json
Code/Configuration Changes
| File | Change |
|---|---|
/mnt/d/Projects/value-first-operations/.editorconfig |
Created — enforces end_of_line = lf for all files |
/mnt/d/.env |
CRLF → LF (57 lines) |
/mnt/d/Projects/value-first-operations/clients/vf-team/.env |
CRLF → LF |
/mnt/d/Projects/value-first-operations/clients/paragon/.env |
CRLF → LF |
26 .env.example files across monorepo |
CRLF → LF on disk |
/mnt/d/.claude/settings.local.json |
Scrubbed 3 hardcoded credentials, removed malformed entry |
Verification
# Confirmed all .env files now have LF endings
file /mnt/d/Projects/value-first-operations/.env
# → ASCII text (no "CRLF" designation)
file /mnt/d/Projects/value-first-operations/clients/vf-team/.env
# → ASCII text
# Confirmed .editorconfig committed and pushed
git -C /mnt/d/Projects/value-first-operations log --oneline -1
# → .editorconfig: Enforce LF line endings across monorepo
Prevention Measures
Rules Added
| Layer | File | Rule |
|---|---|---|
| Critical Lessons | memory/MEMORY.md |
"CRLF line endings in .env files cause silent token failures. .editorconfig enforces LF. If new .env files appear with CRLF, convert with sed -i 's/\r$//'. Windows-created files are always suspect." |
| Enforcement | skills/enforcement/vf-self-correction.md |
Detection trigger: if token loading fails or API returns 401, check file line endings before assuming token is invalid |
| Enforcement | CLAUDE.md Step 4 |
Enforcement skills must be read at session start — enforcement loading is now MANDATORY, not optional |
| Operations | memory/operations.md |
Infrastructure health note: CRLF prevention active via .editorconfig + .gitattributes |
| Instruction Optimizer | agents/instruction-optimizer/data/incident-log.json |
Incident logged for pattern analysis |
Detection Triggers
- If
source .envproduces no errors but API calls return 401 → Checkfile path/to/.envfor CRLF designation - If Claude hardcodes a token inline in a bash command → The normal token loading path is broken. Stop and fix the root cause instead of working around it.
- If
settings.local.jsoncontains literal API tokens → Credential leakage from a broken token loading path. Scrub immediately and fix the underlying issue.
Lessons
The most dangerous bugs are the silent ones. CRLF line endings don't throw errors — they corrupt values invisibly, and every workaround (hardcoding tokens) creates a new problem (credential leakage). Cross-platform development on Windows/WSL requires explicit encoding enforcement at every layer: .gitattributes for tracked files, .editorconfig for all files, and awareness that gitignored files (.env) fall through both nets.
The deeper lesson: when AI systems can't find the credentials they need through normal channels, they improvise — and the improvisations leave artifacts. Leaked credentials in settings.local.json weren't a security incident; they were symptoms of infrastructure failure. Treat improvised workarounds as diagnostic signals, not as the problem itself.
Related Incidents
- HubSpot Broadcast API no draft mode (Feb 18) — Another "silent behavior" incident where missing configuration caused unintended side effects
- Substring date matching (Feb 21) — Another data format issue where invisible differences in strings caused wrong matches
- Portal Documents filter mismatch (Mar 2) — Exact-match requirement where a slightly wrong value caused invisible failures