🎓 A1Learner
🔍
0 of 45 lessons completed

Bash Script Hardening Checklist

A Bash script hardening checklist is a fixed set of checks applied to a script before it runs. Each check maps to one safety rule, and a script ships only when every check passes.

An audit counts flaws in a sample script

A sample script holds one dangerous line, one unquoted remove, and one safely quoted copy. The audit counts each pattern separately.

printf 'eval "$cmd"\nrm $file\ncp "$src" "$dst"\n' > target.sh
echo "eval count: $(grep -c -F eval target.sh)"
echo "unquoted rm count: $(grep -c -F 'rm $' target.sh)"
echo "quoted copy count: $(grep -c -F 'cp "$src"' target.sh)"

A clean script counts zero flaws

The fixed script quotes its copy and guards its remove with --. Both danger counts fall to zero.

printf 'cp "$src" "$dst"\nrm -- "$file"\n' > fixed.sh
echo "eval count: $(grep -c -F eval fixed.sh)"
echo "unquoted rm count: $(grep -c -F 'rm $' fixed.sh)"

Safe settings handle crafted names at once

Noclobber, pipefail, and a strict mask are all switched on. The quoted loop checks a spaced name and a dash-led name, and the spaced file lands private.

set -o noclobber
set -o pipefail
umask 077
printf 'x\n' > "a b.txt"
printf 'x\n' > ./-n.txt
count=0
for f in *.txt; do
  count=$((count+1))
  printf 'checked: %s\n' "$f"
done
echo "count: $count"
stat -c %a "a b.txt"

Example

printf 'cp "$src" "$dst"\nrm -- "$file"\n' > sample.sh
fail=0
if grep -q -F eval sample.sh; then
  echo "eval: FAIL"
  fail=1
else
  echo "eval: PASS"
fi
if grep -q -F 'rm $' sample.sh; then
  echo "unquoted rm: FAIL"
  fail=1
else
  echo "unquoted rm: PASS"
fi
if grep -q -F '"$src"' sample.sh; then
  echo "quoting: PASS"
else
  echo "quoting: FAIL"
  fail=1
fi
umask 077
printf 'x\n' > audit.txt
echo "umask mode: $(stat -c %a audit.txt)"
echo "failures: $fail"

Key points

  • Quote check: every variable expansion that holds a filename or value is quoted.
  • Option check: commands that take filenames use -- or a ./ prefix for dash-led names.
  • Eval check: the script contains no eval on untrusted input, with a safe alternative instead.
  • Environment check: PATH is fixed and untrusted variables are dropped before outside commands run.
  • Overwrite check: noclobber is on, and every deliberate overwrite uses >| on purpose.
  • Pipeline check: pipefail is on, so a failed early pipeline stage cannot hide.
  • Mode check: umask is set before secret files are created, and modes are verified with stat.

In this example, a sample script is checked rule by rule. The eval check and the unquoted-rm check both pass because neither pattern appears. The quoting check passes because the quoted source is present, and the secret audit file is created under the strict mask with no failures recorded.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

An audit finds eval on user input in a script. What is the hardening response?