Summary
fga model test --tests accepts a glob (filepath.Glob, cmd/model/test.go:75) and loops over every match. If a matched file is a FIFO with no writer, os.ReadFile blocks waiting for data that never arrives and the CLI hangs until it is killed.
Reproduction
mkdir repo && cd repo
cat > ok.fga.yaml <<'YAML'
name: ok
model: |
model
schema 1.1
type user
tuples: []
tests: []
YAML
mkfifo evil.fga.yaml
fga model test --tests "*.fga.yaml"
Hangs indefinitely; needs Ctrl-C or SIGKILL. evil.fga.yaml was never named — the glob picked it up.
Reachability
A FIFO can't be committed to git (git add skips it), so this doesn't survive git clone. What does work:
- an extracted tarball or zip (
tar preserves FIFOs)
- a mounted volume or shared directory
- a committed symlink to a FIFO path that already exists on the victim's machine (symlinks do survive
git clone)
Impact is a wedged terminal or CI job. A symlink to /dev/zero is also reachable but doesn't hang — the read terminates and YAML parsing fails with control characters are not allowed.
Prior art
- kubectl doesn't check file type.
ExpandPathsToFileVisitors (cli-runtime/pkg/resource/visitor.go) filters only directories and extensions during filepath.Walk, and FileVisitor.Visit does a bare os.Open. It streams rather than buffers.
- Terraform checks, and distinguishes named paths from glob matches (
internal/lang/funcs/filesystem.go). fileexists errors per irregular type — "is a device node", "is a named pipe", "is a unix domain socket". fileset, which globs, does os.Stat per match and continues past anything where !fi.Mode().IsRegular().
Suggested direction
Skip non-regular matches after filepath.Glob, following fileset. That leaves explicitly named paths alone, so --tests <(...) and --file <(...) keep working.
Whether an explicitly named non-regular path should error or be read as it is today is a separate decision.
Summary
fga model test --testsaccepts a glob (filepath.Glob,cmd/model/test.go:75) and loops over every match. If a matched file is a FIFO with no writer,os.ReadFileblocks waiting for data that never arrives and the CLI hangs until it is killed.Reproduction
Hangs indefinitely; needs Ctrl-C or SIGKILL.
evil.fga.yamlwas never named — the glob picked it up.Reachability
A FIFO can't be committed to git (
git addskips it), so this doesn't survivegit clone. What does work:tarpreserves FIFOs)git clone)Impact is a wedged terminal or CI job. A symlink to
/dev/zerois also reachable but doesn't hang — the read terminates and YAML parsing fails withcontrol characters are not allowed.Prior art
ExpandPathsToFileVisitors(cli-runtime/pkg/resource/visitor.go) filters only directories and extensions duringfilepath.Walk, andFileVisitor.Visitdoes a bareos.Open. It streams rather than buffers.internal/lang/funcs/filesystem.go).fileexistserrors per irregular type — "is a device node", "is a named pipe", "is a unix domain socket".fileset, which globs, doesos.Statper match andcontinues past anything where!fi.Mode().IsRegular().Suggested direction
Skip non-regular matches after
filepath.Glob, followingfileset. That leaves explicitly named paths alone, so--tests <(...)and--file <(...)keep working.Whether an explicitly named non-regular path should error or be read as it is today is a separate decision.