- Posted on
- • Artificial Intelligence
Bash Scripts That Explain Security Risks
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Bash Scripts That Explain Security Risks
Ever run a “quick” Bash one-liner from the web—or glued a few commands together to automate a task—only to wonder if it’s safe? The smallest mistake in a shell script can escalate fast: data loss, credential leaks, or remote code execution. This post uses short, readable Bash snippets to show common security pitfalls and how to fix them—so you can keep the power of Bash without the booby traps.
What you’ll get:
A mental model for why Bash security risks are real and worth your time
5 focused examples of risky patterns, each with a safer alternative
A quick tooling tip to catch issues automatically
Distro-specific installation commands where tools are cited
Note: All examples are crafted to be safe to copy-paste in a test directory. They print or operate on /tmp paths, not on production data.
Why this matters
Bash is everywhere: CI/CD runners, cron jobs, Docker entrypoints, ad-hoc admin scripts, and “quick fixes” that stick around for years.
Shell syntax is sharp: quoting, word splitting, globbing, and environment inheritance are powerful—and easy to misuse.
Real incidents happen because of small mistakes: an unquoted variable, a predictable temp file, or an over-trusting
evalcan hand control to attackers.Risk rises with privilege: many scripts run as root or on critical hosts. Low-probability mistakes + high-impact context = worth fixing.
Prerequisites (tooling)
We’ll use ShellCheck to statically lint our examples. If you don’t have it, install it with your distro’s package manager.
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y shellcheck
- Fedora/RHEL/CentOS Stream (dnf):
sudo dnf install -y ShellCheck
- openSUSE/SLE (zypper):
sudo zypper refresh
sudo zypper install -y ShellCheck
# If that fails, try the lowercase name:
# sudo zypper install -y shellcheck
Run it like:
shellcheck your-script.sh
1) Unquoted variables cause word splitting and globbing
The risk:
Unquoted expansions (like
$var) split on whitespace and expand globs (*,?).Attackers (or accidents) can change what your command means by adding spaces or glob characters.
Vulnerable:
#!/usr/bin/env bash
# demo1-bad.sh
src=$1
dest_dir=$2
mkdir -p $dest_dir
cp $src $dest_dir/
How it can go wrong:
- If
$srcisreport 2026*.txt, the*will expand inside the script and copy many files you didn’t intend.
Safer:
#!/usr/bin/env bash
# demo1-good.sh
set -euo pipefail
src=$1
dest_dir=$2
mkdir -p -- "$dest_dir"
cp -- "$src" "$dest_dir/"
Key takeaways:
Always quote variables:
"$var".Use
--to end option parsing when passing user input to commands.Consider
set -euo pipefailto fail early and avoid using unset variables.
2) Command injection via eval and unsafe composition
The risk:
- Building shell commands from strings and running them with
evallets attackers smuggle in new commands.
Vulnerable:
#!/usr/bin/env bash
# demo2-bad.sh
pattern=$1
cmd="grep $pattern access.log"
eval "$cmd"
If pattern is foo; echo HACKED >&2, the echo will also run.
Safer (don’t use eval; pass args directly):
#!/usr/bin/env bash
# demo2-good.sh
set -euo pipefail
pattern=$1
grep -- "$pattern" access.log
Key takeaways:
Avoid
evalfor untrusted input. Prefer arrays or direct argument passing.Many tools support
--to prevent input from being treated as options.
3) Insecure temporary files (symlink and race attacks)
The risk:
Writing to a predictable path in
/tmplets attackers pre-create a symlink to a sensitive file.Result: your script overwrites something you never intended.
Vulnerable:
#!/usr/bin/env bash
# demo3-bad.sh
tmp=/tmp/myapp.log
echo "report at $(date)" > "$tmp"
echo "Wrote $tmp"
Safer:
#!/usr/bin/env bash
# demo3-good.sh
set -euo pipefail
umask 077 # Restrictive defaults: files 600, dirs 700
tmp=$(mktemp -t myapp.XXXXXX)
trap 'rm -f "$tmp"' EXIT
printf 'report at %s\n' "$(date)" > "$tmp"
echo "Wrote $tmp (will be removed on exit)"
Key takeaways:
Use
mktempfor unique files/dirs (mktemp -dfor directories).Set a restrictive
umask(e.g.,077) to avoid world-readable secrets.Clean up with
trap ... EXIT.
4) PATH hijacking and untrusted environment
The risk:
- If your script trusts
$PATH, an attacker can place a malicious binary earlier in the path (or in.) and your script will run it.
Vulnerable:
#!/usr/bin/env bash
# demo4-bad.sh
PATH=.:$PATH # Don't do this
tar czf /tmp/backup.tgz /var/log
Safer (set a known-good PATH and/or use absolute paths):
#!/usr/bin/env bash
# demo4-good.sh
set -euo pipefail
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
TAR=$(command -v tar) || { echo "tar not found" >&2; exit 1; }
"$TAR" czf /tmp/backup.tgz -- /var/log
Key takeaways:
Never prepend
.to PATH.Set a minimal, known-safe PATH at script start.
Resolve tools with
command -vor use absolute paths.
5) Leaking secrets via args and debug traces
The risk:
set -x(xtrace) prints commands and their expanded arguments, exposing tokens/passwords in logs.Secrets in command-line args may be visible to other processes via
ps(depending on system/policy).
Vulnerable:
#!/usr/bin/env bash
# demo5-bad.sh
set -x
token=$1
curl -H "Authorization: Bearer $token" https://api.example.com/me
Safer:
#!/usr/bin/env bash
# demo5-good.sh
set -euo pipefail
set +x # ensure xtrace is off before handling secrets
token=$1
# Avoid logging the token; prefer config, files with 600 perms, or stdin where possible.
curl -sS -H "Authorization: Bearer $token" https://api.example.com/me > /tmp/me.json
# If you must re-enable xtrace later:
# set -x
Further hardening ideas:
Avoid placing secrets in command-line args; consider reading from stdin (
read -rs secret) and passing via headers or files withchmod 600.Keep debug logs separated from production runs; never enable
set -xin secret-handling code paths.
Bonus: Guardrails to put in every script
Drop this near the top of your scripts:
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# Optional: minimal, known-safe PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Cleanup example
# tmp=$(mktemp -t myapp.XXXXXX); trap 'rm -f "$tmp"' EXIT
Why it helps:
-estops on errors;-ufails on unset vars;pipefailpropagates failures in pipelines.A strict
IFSreduces accidental word splitting.A known PATH limits hijacking risk.
Linting: let ShellCheck catch mistakes early
Run:
shellcheck demo1-bad.sh
ShellCheck will point out:
Unquoted variables
Useless/unsafe
evalWord splitting issues
Globbing pitfalls
Many more best practices
This is the fastest, highest-ROI step you can take today.
Conclusion and next steps (CTA)
Pick one production script you rely on.
Add
set -euo pipefail, quote every variable, lock down PATH, and fix temp file handling withmktemp.Run
shellcheckand address its warnings.Repeat for your other scripts; make this your team’s standard.
Security in Bash isn’t about writing less shell—it’s about writing it deliberately. Start with the five pitfalls above, bake the guardrails into your templates, and let ShellCheck keep you honest. Your future self (and your incident report) will thank you.