Why POSIX wordexp(3) Is Dangerous on Untrusted Input

Translated by a model; the original is in Russian.

· Security
POSIX's wordexp(3), often recommended for tilde expansion, performs command substitution by default — and the WRDE_NOCMD flag doesn't always save you.

cover.svg

POSIX's wordexp(3) is frequently recommended as a convenient way to do shell-style expansions from C — for instance, turning ~/foo into /home/me/foo. The code looks harmless: call wordexp(), take the first element of we_wordv, free it with wordfree(). For tilde expansion, that's all you need.

The trouble hides in the last argument: the flags parameter. When it's 0, every expansion feature is enabled by default — including command substitution. That means an input like $(whoami)/foo or $(cat /etc/passwd)/foo will be dutifully executed by the shell. Your innocent "path-expanding helper" quietly becomes arbitrary command execution.

WRDE_NOCMD doesn't help everywhere

There is, apparently, a cure: the WRDE_NOCMD flag, which is supposed to forbid command substitution. But the author warns that in some libc implementations this is palliative at best.

musl implements wordexp(3) by simply delegating to the system shell. Before doing so it runs a cursory scan for command substitutions, but the check is incomplete: some constructs that the underlying shell (such as GNU Bash) happily treats as valid substitutions slip past musl's matching.

macOS works much the same way: its libc hands the job off to a helper process, /usr/lib/system/wordexp-helper. According to Julian Squires, as recently as 2023 the same bypass worked here as in musl. The author didn't bother testing whether it still does now that macOS's default shell is zsh rather than bash. (A curious footnote: macOS's wordexp(3) used to shell out to Perl — wordexp-helper appears to be the "modern" replacement.)

The bottom line

Don't use wordexp(3) on untrusted inputs, even with WRDE_NOCMD. If all you want is tilde expansion, you're better off doing it by hand rather than handing the string to a shell.


Source: Lobsters

Comments

Sign in, to comment.

  • No comments yet.