Skip to content
shellhacks.dev
Security

Validate input with a whitelist

Validate input against a list of allowed values with a case statement. A grep check with ^ and $ can be fooled by a value that holds a newline.

1 min read
Summarize in AI

A script takes an action name from outside and must refuse everything that is not on a short list.

Shell
validate() { case $1 in start|stop|status) return 0 ;; *) return 1 ;; esac; }
for a in start 'start; reboot' ''; do
  validate "$a" && echo "ok:       [$a]" || echo "rejected: [$a]"
done
echo ---
input=$'start\nrm -rf /'
printf '%s' "$input" | grep -qE '^(start|stop)$' && echo "grep: accepted" || echo "grep: rejected"
validate "$input" && echo "case: accepted" || echo "case: rejected"
Text
ok:       [start]
rejected: [start; reboot]
rejected: []
---
grep: accepted
case: rejected

A case pattern must match the whole string, so only the three exact words pass, and anything else, including the empty value, falls through to the default. grep works one line at a time and its anchors match at each line, so a value that holds a newline passes if any single line looks right. Here the first line is start, and the dangerous second line is never examined. The matching rules are in the Bash manual.

The list approach fits a short set of fixed words. For a format, such as a number or a host name, [[ $x =~ ^[0-9]+$ ]] in Bash matches the whole string, though a trailing newline can still slip through $, so check with a character class that excludes newlines first. Validate where the value is used, not only where it arrives.

Share

More snippets

Security

Avoid predictable temp names

Never build a temp file name from $$ or a fixed string. An attacker who guesses it can plant a symlink, and mktemp picks an unused random name with mode 600.

1 min read
Security

Quote variables passed to commands

Quote variables you pass to commands. An unquoted expansion splits on spaces and expands globs, and a value that starts with a dash becomes an option.

1 min read
Security

Avoid eval on input

Never pass input to eval. Run a command held in an array as "${cmd[@]}", or escape a value with printf %q when eval cannot be avoided.

1 min read

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.