🎓 A1Learner
🔍
0 of 45 lessons completed

Bash Globbing Attacks

Bash globbing attacks use crafted filenames to change what a wildcard command touches. A safe script quotes every expansion and never lets a filename act as an option or as several words.

Unquoted expansion splits one name into pieces

Two text files are created, one with a space in its name. The quoted array counts two files, but the unquoted loop counts three pieces.

printf 'x\n' > "a b.txt"
printf 'x\n' > "c.txt"
files=(*.txt)
echo "count: ${#files[@]}"
for f in ${files[@]}; do echo "piece: $f"; done

A dash filename is read as an option

A file named -n holds one word. Plain cat treats -n as its own option and reads empty input instead of the file. The -- form forces cat to treat -n as a filename.

printf 'hello\n' > ./-n
echo "without dashdash:"
cat -n
echo "with dashdash:"
cat -- -n

An unmatched pattern stays literal

No text file exists in this empty directory. Nullglob counts zero matches, while the default setting leaves the pattern as the literal word.

shopt -s nullglob
files=(*.txt)
echo "count: ${#files[@]}"
shopt -u nullglob
for f in *.txt; do echo "literal: $f"; done

Example

printf 'x\n' > "a b.txt"
printf 'x\n' > ./-n.txt
printf 'x\n' > keep.txt
safe=0
for f in *.txt; do
  safe=$((safe+1))
  printf 'checked: %s\n' "$f"
done
echo "safe count: $safe"
broken=0
for f in *.txt; do
  for part in $f; do
    broken=$((broken+1))
  done
done
echo "broken count: $broken"

Key points

  • Unquoted expansion: an unquoted variable splits on spaces and expands wildcards again.
  • Quoted expansion: quotes keep one filename as one word, spaces included.
  • Leading dash: a filename starting with a dash can be read as an option by the next command.
  • Dash defence: put -- before filenames, or prefix them with ./, so no name is read as an option.
  • Empty match: with no match, a pattern stays literal by default instead of expanding to nothing.
  • Nullglob: shopt -s nullglob makes an unmatched pattern expand to nothing.
  • Count check: count matches before acting, so an empty or huge match cannot surprise the script.

In this example, three files are created, including one with a space and one starting with a dash. The first loop quotes each name, so it checks three files exactly once each. The second loop leaves each name unquoted, so the spaced name splits into two pieces and the count rises to four.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A script loops over *.txt files with an unquoted variable. One file is named "a b.txt". What goes wrong?