Describe the bug
doppler secrets substitute crashes with an unhandled panic (index out of range [1] with length 1) when the process environment contains an entry without an = separator.
utils.ParseEnvStrings (pkg/utils/env.go) assumes every os.Environ() entry is in key=value format and indexes parts[1] without a length check. Go does not filter =-less entries from os.Environ() — a process can legitimately receive one when its parent builds the environ array directly (e.g. a C/Rust/Python parent calling execve with a crafted envp). Standard shells refuse this (env -i NOEQ errors), but the raw exec path is reachable.
In dev builds this surfaces as a raw panic with a stack trace; in release builds the recover() handler in pkg/cmd/root.go catches it and prints Doppler Exception:, but the command still fails.
To Reproduce
-
Exec the CLI with an environ entry lacking = (requires a parent that calls execve directly):
#include <unistd.h>
int main(int argc, char **argv) {
char *envp[] = {"NOEQ", "HOME=/root", "PATH=/usr/bin:/bin", NULL};
char *av[] = {argv[1], "secrets", "substitute", "template.txt", "--use-env=only", NULL};
execve(argv[1], av, envp);
return 1;
}
-
template.txt can be any file, e.g. echo 'Hello {{.NOPE}}' > template.txt
-
Run the compiled wrapper: ./execenv /path/to/doppler
Observed (dev build):
panic: runtime error: index out of range [1] with length 1
goroutine 1 [running]:
github.com/DopplerHQ/cli/pkg/utils.ParseEnvStrings({0xc0002f7d10, 0x3, 0x6?})
/tmp/doppler-cli/pkg/utils/env.go:27 +0x105
github.com/DopplerHQ/cli/pkg/cmd.substituteSecrets(0x10007c0, {0xc000302540, 0x1, 0xa87220?})
/tmp/doppler-cli/pkg/cmd/secrets.go:596 +0x29c
...
Expected behavior
Environment entries missing = should be skipped or tolerated rather than crashing the command.
Suggested fix (one-liner in pkg/utils/env.go / ParseEnvStrings):
parts := strings.SplitN(envVar, "=", 2)
if len(parts) != 2 {
continue // ignore malformed entries
}
Desktop (please complete the following information):
- OS: Linux
- Version 7.0.0-28-generic
CLI Version:
Built from source @ b618e5f (version dev); the issue is present in current main (pkg/utils/env.go:27).
Additional context
Found during a security review of the CLI. Judged robustness-only (release builds catch the panic, and the environment is set by the parent process), so I'm filing this as a bug rather than a security report. Happy to open a PR with the fix.
Describe the bug
doppler secrets substitutecrashes with an unhandled panic (index out of range [1] with length 1) when the process environment contains an entry without an=separator.utils.ParseEnvStrings(pkg/utils/env.go) assumes everyos.Environ()entry is inkey=valueformat and indexesparts[1]without a length check. Go does not filter=-less entries fromos.Environ()— a process can legitimately receive one when its parent builds the environ array directly (e.g. a C/Rust/Python parent callingexecvewith a craftedenvp). Standard shells refuse this (env -i NOEQerrors), but the raw exec path is reachable.In dev builds this surfaces as a raw panic with a stack trace; in release builds the
recover()handler inpkg/cmd/root.gocatches it and printsDoppler Exception:, but the command still fails.To Reproduce
Exec the CLI with an environ entry lacking
=(requires a parent that callsexecvedirectly):template.txtcan be any file, e.g.echo 'Hello {{.NOPE}}' > template.txtRun the compiled wrapper:
./execenv /path/to/dopplerObserved (dev build):
Expected behavior
Environment entries missing
=should be skipped or tolerated rather than crashing the command.Suggested fix (one-liner in
pkg/utils/env.go/ParseEnvStrings):Desktop (please complete the following information):
CLI Version:
Built from source @ b618e5f (version
dev); the issue is present in currentmain(pkg/utils/env.go:27).Additional context
Found during a security review of the CLI. Judged robustness-only (release builds catch the panic, and the environment is set by the parent process), so I'm filing this as a bug rather than a security report. Happy to open a PR with the fix.