Skip to content

fix: nil pointer panic in getDefaultInstallDir on containerized Linux#2339

Merged
jribbink merged 1 commit intoonflow:masterfrom
nvdtf:fix/nil-ptr-default-install-dir-container
May 4, 2026
Merged

fix: nil pointer panic in getDefaultInstallDir on containerized Linux#2339
jribbink merged 1 commit intoonflow:masterfrom
nvdtf:fix/nil-ptr-default-install-dir-container

Conversation

@nvdtf
Copy link
Copy Markdown
Member

@nvdtf nvdtf commented May 4, 2026

Summary

flow CLI panics immediately on startup with a nil pointer dereference in containerized Linux environments (Docker, CI runners, Kubernetes pods, etc.) where the running UID is not present in /etc/passwd.

Root Cause

In internal/settings/defaults.go, getDefaultInstallDir() calls user.Current() from Go's os/user package to resolve the home directory:

// Before (Linux branch)
usr, _ := user.Current() // safe to ignore cache errors
return fmt.Sprintf(`%s/.local/bin`, usr.HomeDir)

The comment "safe to ignore cache errors" is misleading and incorrect in this context. user.Current() can fail in two distinct ways:

  1. Cache/NSS errors — a transient lookup failure where usr may still be partially populated. Ignoring these might be tolerable.
  2. UID not in /etc/passwd — the process UID has no corresponding entry in the user database. In this case user.Current() returns nil, err. Ignoring the error and then accessing usr.HomeDir dereferences a nil pointer.

Because getDefaultInstallDir() is called during package init() (it's used as a map literal value in defaults), the panic fires before main() runs. There is no way to recover from it — flow version, flow help, and every other subcommand all crash identically.

Why this is common

Containerized environments routinely run processes under UIDs that are not registered in /etc/passwd:

  • Docker images built FROM scratch or minimal base images (alpine, distroless) often omit /etc/passwd entries for dynamically assigned UIDs
  • Kubernetes runAsUser / runAsNonRoot security contexts frequently assign arbitrary UIDs
  • CI systems (GitHub Actions, GitLab CI, BuildKit) sometimes run steps under UIDs injected at runtime that don't exist in the image's /etc/passwd
  • The same issue applies to any chroot environment without a fully populated /etc/passwd

Reproduction

FROM ubuntu:22.04
COPY flow /usr/local/bin/flow
# Run as a UID that has no /etc/passwd entry
USER 12345
CMD ["flow", "version"]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x1da23f0]

goroutine 1 [running]:
github.com/onflow/flow-cli/internal/settings.getDefaultInstallDir()
	/go/src/github.com/onflow/flow-cli/internal/settings/defaults.go:57 +0x20
github.com/onflow/flow-cli/internal/settings.init()
	/go/src/github.com/onflow/flow-cli/internal/settings/defaults.go:35 +0x70

Fix

Replace user.Current() with os.UserHomeDir(), which is the idiomatic Go way to resolve the home directory. os.UserHomeDir() uses the following resolution order:

  1. Calls user.Current() internally on most platforms
  2. Falls back to the $HOME environment variable if the syscall lookup fails

This means it works correctly in all the environments where user.Current() panics, as long as $HOME is set (which it almost always is, even in minimal containers). If $HOME is also absent, it returns an error, which we handle gracefully by returning an empty string — a safe no-op rather than a crash.

The fix also removes the os/user import (now unused) and applies the same correction to the Windows branch, which has the identical vulnerability.

// After (Linux branch)
homeDir, err := os.UserHomeDir()
if err != nil {
    return ""
}
return fmt.Sprintf(`%s/.local/bin`, homeDir)

Impact

  • Before: flow CLI is completely unusable in any containerized Linux environment where the process UID is not in /etc/passwd. Every command panics at startup.
  • After: flow CLI starts correctly in all environments where $HOME is set, and fails gracefully (returns an empty default path) in the rare case where neither /etc/passwd nor $HOME is available.

Testing

To verify the fix, build the CLI and run it inside a container with a synthetic UID:

docker run --rm -u 99999 -v $(which flow):/usr/local/bin/flow ubuntu:22.04 flow version

Before this fix: immediate panic. After: normal output.

@nvdtf
Copy link
Copy Markdown
Member Author

nvdtf commented May 4, 2026

I asked https://github.com/qwibitai/nanoclaw to install Flow CLI and it couldn't. The agent opened this PR as root cause of why it couldn't install Flow CLI in it's limited container.

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/settings/defaults.go 0.00% 8 Missing ⚠️

📢 Thoughts on this report? Let us know!

@jribbink jribbink merged commit 6a01e03 into onflow:master May 4, 2026
9 checks passed
@nvdtf nvdtf deleted the fix/nil-ptr-default-install-dir-container branch May 4, 2026 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants