feat: support configurable quote character for dotenv export - #389
mateuscmtropical wants to merge 2 commits into
Conversation
`infisical export` always wrapped values in single quotes. Single quoted dotenv values have no escape sequences, so a multiline value (e.g. a PEM private key) can't be represented with a real newline. Adds --dotenv-quote-char (default: '), letting the value be wrapped in double quotes instead, which lets the existing multiline encoding decode back into a real newline on read. Only affects the dotenv/dotenv-export formats; validated up front, before any network call. Closes Infisical/infisical#1103
|
| Filename | Overview |
|---|---|
| packages/cmd/export.go | Adds configurable dotenv quoting, but applies verbatim double-quoted values to shell-oriented dotenv-export output, enabling shell interpretation. |
| packages/cmd/export_test.go | Adds broad unit coverage for formatting and validation, although it does not test shell consumption of double-quoted dotenv-export output. |
Reviews (1): Last reviewed commit: "feat: support configurable quote charact..." | Re-trigger Greptile
| // something parsers only do for double quoted values. That is the whole reason | ||
| // to pick it over the single quote default. | ||
| func quoteDotEnvValue(env models.SingleEnvironmentVariable, quoteChar string) string { | ||
| return quoteChar + escapeNewLinesIfRequired(env) + quoteChar |
There was a problem hiding this comment.
Double Quotes Enable Injection
When dotenv-export uses the new double-quote mode, secret contents remain active shell syntax. A value such as $(command) is emitted as export KEY="$(command)", so sourcing the generated shell-environment output executes the command. Embedded double quotes can also end the assignment and inject more shell syntax. Keep dotenv-export shell-safe regardless of the selected quote character, or reject double-quote mode for this format.
How this was verified: Arbitrary secret values flow directly into a double-quoted export assignment without escaping command substitutions, backticks, dollar signs, or double quotes.
Knowledge Base Used: Secret workflows
The repo's review bot flagged that --dotenv-quote-char's double-quote mode let a secret containing $(cmd) or a backtick execute code when the dotenv-export output was sourced by a shell. Investigating further turned up that this output was never safe to source, independent of this flag: the default single-quote wrapping didn't escape an embedded single quote in the value, and the secret's own name was interpolated completely unescaped, so a secret named e.g. "FOO=bar; touch pwned #" or one starting with "-" (misread as an export flag, which on dash dumps the whole environment to stdout) also executed or leaked on source. A name containing "=" or ending in "+" let a secret silently overwrite or append to an unrelated variable (PATH, LD_PRELOAD, ...), since export re-parses NAME=VALUE/NAME+=VALUE after quote removal regardless of quoting. dotenv-export now delegates to dotenv-eval's existing posixShellQuote for the value, and a secret name is only accepted if it matches a portable shell variable name; anything else aborts the export with an error instead of producing a partial or unsafe file. --dotenv-quote-char no longer affects dotenv-export (always wrapped safely) or dotenv-eval (already was); it still works as before for the plain dotenv format. Verified each finding by hand: generating the real output and sourcing it in bash, dash and sh, both before and after the fix. Reviewed adversarially across several rounds by independent AI models until no new finding surfaced.
Description 📣
Implements #1103 (possibility to export env-s with different quote character).
infisical exportalways wrapped values in single quotes. Single quoted dotenv values have no escape sequences, so a multiline value (e.g. a PEM private key) can't be represented with a real newline — you'd have to post-process the file afterward.--dotenv-quote-char(default', existing output unchanged), accepting'or"dotenvformat now (see security fix below for whydotenv-exportwas excluded)--templatepathSecurity fix (added after review)
The repo's automated reviewer flagged that double-quote mode combined with
--format=dotenv-exportlet a secret containing$(cmd)execute code when the output was sourced by a shell. Investigating further turned up thatdotenv-export's output was never safe tosource, independent of this PR:'in the value:and/in a secret name, so;,$,=, space are all valid)-(e.g.-p) got read as anexportflag — ondashthis dumps the whole environment to stdout instead of failing=or ending in+let a secret silently overwrite or append to an unrelated variable (PATH,LD_PRELOAD, ...), sinceexportparsesNAME=VALUE/NAME+=VALUEafter quote removal regardless of quotingFix:
dotenv-exportnow delegates todotenv-eval's existingposixShellQuotefor the value, and a secret name is only accepted if it matches a portable shell variable name (^[A-Za-z_][A-Za-z0-9_]*$); anything else aborts the export with an error instead of producing a partial or unsafe file.--dotenv-quote-charno longer applies todotenv-export(always wrapped safely) ordotenv-eval(already was).Breaking change:
dotenv-export/dotenv-evaloutput is nowexport -- KEY='VALUE'(wasexport KEY='VALUE'), and a secret name that isn't a valid shell identifier now fails the whole export instead of producing a line that silently misbehaves onsource. A secret literally named after a shell control variable (PATH,IFS,LD_PRELOAD, ...) is intentionally still allowed — that's the name being used with its expected effect, not smuggling, and isn't something this CLI can safely second-guess.Every finding above was verified by hand (built the real output, sourced it in
bash/dash/sh, confirmed the exploit before the fix and its absence after) and reviewed adversarially across independent rounds by multiple AI models before being folded in here.Type ✨
Tests 🛠️
Ran
go test ./packages/cmd/... -vet=off -count=1(all passing).Verified against the real
dotenvnpm package that double-quoted output round-trips correctly for values with trailing backslashes, embedded quotes, backslash+quote combinations, and multiline private keys:Verified the shell-injection fix by generating
dotenv-export/dotenv-evaloutput for adversarial secrets and sourcing it inbash,dashandsh: