* Interpolate $VAR_NAME and ${VAR_NAME} patterns in a string using process.env, * but only for variable names present in the allowlist. References to variables * not in the allowlist are replaced with empty strings to prevent exfiltration * of secrets via project-configured HTTP hooks. * * The
( value: string, allowedEnvVars: ReadonlySet<string>, )
| 87 | * The result is sanitized to strip CR/LF/NUL bytes to prevent header injection. |
| 88 | */ |
| 89 | function interpolateEnvVars( |
| 90 | value: string, |
| 91 | allowedEnvVars: ReadonlySet<string>, |
| 92 | ): string { |
| 93 | const interpolated = value.replace( |
| 94 | /\$\{([A-Z_][A-Z0-9_]*)\}|\$([A-Z_][A-Z0-9_]*)/g, |
| 95 | (_, braced, unbraced) => { |
| 96 | const varName = braced ?? unbraced |
| 97 | if (!allowedEnvVars.has(varName)) { |
| 98 | logForDebugging( |
| 99 | `Hooks: env var $${varName} not in allowedEnvVars, skipping interpolation`, |
| 100 | { level: 'warn' }, |
| 101 | ) |
| 102 | return '' |
| 103 | } |
| 104 | return process.env[varName] ?? '' |
| 105 | }, |
| 106 | ) |
| 107 | return sanitizeHeaderValue(interpolated) |
| 108 | } |
| 109 | |
| 110 | /** |
| 111 | * Execute an HTTP hook by POSTing the hook input JSON to the configured URL. |
no test coverage detected