fix: improve settings distributor robustness and security#12
Conversation
- Fix TOML string escaping to handle newlines, tabs, carriage returns - Fix TOML inline table parsing to handle commas in quoted strings - Fix TOML scalar insertion to only target top-level keys, avoid section overwrites - Add warning for Cursor project-level permission limitations per security advisory - Add warning for unsupported Codex permission keys to clarify what's actually mapped - Deduplicate SETTINGS_TARGETS constant and resolveTargets logic across modules - Add process.env fallback for env resolution (after file lookup) - Add .env.agents to default lookup order for dedicated agent secrets - Improve test coverage for new fallback behavior Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
| return inner | ||
| .replace(/\\n/g, '\n') | ||
| .replace(/\\r/g, '\r') | ||
| .replace(/\\t/g, '\t') | ||
| .replace(/\\"/g, '"') | ||
| .replace(/\\\\/g, '\\'); |
There was a problem hiding this comment.
🟡 Sequential regex replacements in unquote corrupt values containing escaped backslashes
The unquote function in src/core/env-resolver.ts:10-15 processes escape sequences using sequential regex replacements in an order that cannot correctly handle escaped backslashes preceding other escape characters like \n, \r, or \t.
Root Cause and Impact
For a .env file containing KEY="hello\\nworld" (intended to represent the literal string hello\nworld), the inner content after stripping quotes is the character sequence h,e,l,l,o,\,\,n,w,o,r,l,d.
Step 1 (replace(/\\n/g, '\n')) matches the second backslash + n first, converting it to a newline character. The first backslash is left as-is, producing hello\<newline>world instead of the intended hello\nworld.
Processing \\ last at step 5 cannot fix this because the \n has already been consumed. Reordering the replacements does not help either—processing \\ first would turn \\n into \n, which step 2 would then convert to a newline.
The fix requires a single-pass replacement, e.g.:
inner.replace(/\\([\\nrt"])/g, (_, ch) => {
const map: Record<string, string> = { '\\': '\\', n: '\n', r: '\r', t: '\t', '"': '"' };
return map[ch] ?? ch;
});Impact: Any double-quoted .env value containing a literal escaped backslash before n, r, t, or " (e.g. Windows paths like C:\\new_folder) will be silently corrupted.
| return inner | |
| .replace(/\\n/g, '\n') | |
| .replace(/\\r/g, '\r') | |
| .replace(/\\t/g, '\t') | |
| .replace(/\\"/g, '"') | |
| .replace(/\\\\/g, '\\'); | |
| return inner | |
| .replace(/\\([\\nrt"])/g, (_, ch) => { | |
| const map: Record<string, string> = { '\\': '\\', n: '\n', r: '\r', t: '\t', '"': '"' }; | |
| return map[ch] ?? ch; | |
| }); |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Fixed multiple bugs in the settings distributor module, added process.env fallback for env resolution, and introduced .env.agents for dedicated agent secrets.
Key fixes:
Test plan
🤖 Generated with Claude Code