UNPKG

env-sentinel

Version:

Zero-dependency tool that auto-validates .env files against schema.env, with optional fallback and secure warnings.

57 lines (56 loc) 1.88 kB
const SHELL_SPECIAL_CHARS = ['$', '`', '!', '*', ';', '|', '&', '>', '<', '?', '(', ')', '{', '}', '[', ']', '=']; export function noUnescapedShellCharsCheck(lineNumber, lineContent) { const equalIndex = lineContent.indexOf('='); if (equalIndex === -1) return; const rawKey = lineContent.slice(0, equalIndex).trim(); let value = lineContent.slice(equalIndex + 1); let cleanValue = ''; let inEscape = false; for (let i = 0; i < value.length; i++) { if (inEscape) { cleanValue += value[i]; inEscape = false; continue; } if (value[i] === '\\') { inEscape = true; cleanValue += value[i]; continue; } if (value[i] === '#') { break; } cleanValue += value[i]; } value = cleanValue.trim(); if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { return; } if (value.includes('\\n') || value.includes('\\r')) { return; } const valueWithoutEnvSubs = value.replace(/\$\{[^}]+}/g, (match) => { return ' '.repeat(match.length); }); for (let i = 0; i < valueWithoutEnvSubs.length; i++) { const ch = valueWithoutEnvSubs[i]; if (SHELL_SPECIAL_CHARS.includes(ch)) { let escapeCount = 0; let j = i - 1; while (j >= 0 && valueWithoutEnvSubs[j] === '\\') { escapeCount++; j--; } if (escapeCount % 2 === 0) { return { line: lineNumber, issue: `Unescaped shell special character '${ch}' in value of "${rawKey}"`, content: lineContent, severity: 'error', }; } } } return; }