bash-script-hardening
Skill22 starsChanged 2 months agoMITView on GitHub
Writes robust, safe, shellcheck-clean Bash scripts using strict mode, defensive quoting, error traps, safe temp files, and signal handling. Use this skill when authoring or reviewing shell/Bash scripts, when asked to "harden a bash script", "add strict mode", "fix shellcheck warnings", "make this script safe", debug silent failures, unquoted-variable bugs, word-splitting/globbing issues, or to add cleanup traps and error handling.
- Deletes or force-pushes
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 4 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 15
Use this skill to author a new script from a hardened template, retrofit an existing script, or review a script for safety defects.
- Very specific: line 19
Set the shebang and strict mode: Use #!/usr/bin/env bash and the canonical strict-mode preamble (see below).
- Distinctive: line 21
Quote everything: Every variable expansion and command substitution gets double quotes unless you have a deliberate, commented reason not …
- Distinctive: line 22
Use arrays for lists and command arguments: Never build commands by concatenating strings.
- Very specific: line 60
Use "${arr[@]}" (quoted, @) to preserve elements.
- Very specific: line 61
Prefer [[ ... ]] over [ ...
- Very specific: line 62
Use printf '%s\n' "$x" instead of echo "$x" for arbitrary data (echo mangles -n, backslashes).
- Very specific: line 106
Never use /tmp/myscript.$$ — predictable names are a symlink-attack vector and collide.
- Very specific: line 143
Separate config from logic: Read tunables from env with documented defaults: : "${TIMEOUT:=30}".
- Distinctive: line 144
Log to stderr, data to stdout: Keep stdout pure so the script composes in pipelines.
- Very specific: line 146
Pin behavior, not the environment: Use full option names in comments.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Bash Script Hardening
Overview
Most Bash bugs are silent: an unset variable expands to nothing, a failed command is ignored, an unquoted path word-splits, and the script marches on corrupting state. This skill makes Bash scripts fail loudly, fail early, and clean up after themselves.
Keywords: bash, shell, strict mode, set -euo pipefail, IFS, quoting, word splitting, globbing, ShellCheck, trap, ERR, EXIT, cleanup, mktemp, signal handling, defensive scripting, POSIX, exit codes, here-doc, arrays.
Use this skill to author a new script from a hardened template, retrofit an existing script, or review a script for safety defects.
Workflow
- Set the shebang and strict mode. Use
#!/usr/bin/env bashand the canonical strict-mode preamble (see below). Never rely on/bin/shif Bash features are used. - Lock down word splitting. Set
IFS=$'\n\t'so unquoted expansions don't split on spaces. - Quote everything. Every variable expansion and command substitution gets double quotes unless you have a deliberate, commented reason not to.
- Use arrays for lists and command arguments. Never build commands by concatenating strings.
- Add a cleanup trap. Register an
EXITtrap that removes temp files and restores state, plus anERRtrap for diagnostics. - Handle errors explicitly where strict mode is insufficient (conditionals, command substitution in older Bash, pipelines you intend to tolerate).
- Create temp files safely with
mktemp, and reference them through the cleanup trap. - Validate inputs and dependencies up front: required args, required commands (
command -v), required env vars. - Run ShellCheck and resolve every finding; suppress only with a justified
# shellcheck disable=SCxxxxcomment. - Test failure paths, not just the happy path.
Reference files:
references/strict-mode.md— deep dive onset -euo pipefail, IFS, and the gotchas/escape hatches.references/shellcheck-codes.md— the most common ShellCheck codes, what they mean, and the correct fix.templates/hardened-script.sh— drop-in starting template with strict mode, traps, arg parsing, logging.scripts/harden_check.sh— static auditor that flags missing strict mode, unquoted vars, and other red flags.examples/before-after.md— a real fragile script transformed into a hardened one, line by line.
The canonical strict-mode preamble
#!/usr/bin/env bash
set -Eeuo pipefail
IFS=$'\n\t'What each flag buys you:
| Flag | Effect | Why it matters |
-e (errexit) | Exit on any command returning non-zero | Stops a broken script from continuing on corrupt state |
-u (nounset) | Error on use of unset variables | Catches typos like "$fle" and missing args |
-o pipefail | A pipeline fails if any stage fails | cmd | grep x no longer hides cmd crashing |
-E (errtrace) | ERR trap is inherited by functions/subshells | Your error trap actually fires inside functions |
IFS=$'\n\t' | Split only on newline/tab, not spaces | Filenames with spaces stop silently breaking loops |
-ehas sharp edges. Readreferences/strict-mode.mdfor where it does NOT trigger (e.g. insideif,&&,||, the last command of a function used as a condition) and the correct patterns to keep error checking explicit there.
Quoting and word-splitting rules
- Always quote expansions:
"$var","${arr[@]}","$(cmd)". - Use
"${arr[@]}"(quoted,@) to preserve elements; never${arr[*]}for argument lists. - Prefer
[[ ... ]]over[ ... ]in Bash — it does not word-split or glob inside. - Use
printf '%s\n' "$x"instead ofecho "$x"for arbitrary data (echo mangles-n, backslashes). - Loop over files with globs or
find -print0 | while IFS= read -r -d '', neverfor f in $(ls).
# WRONG — word-splits and globs
for f in $(ls *.txt); do rm $f; done
# RIGHT
shopt -s nullglob
for f in ./*.txt; do
rm -- "$f"
doneTraps and cleanup
Register cleanup once, early, and make it idempotent:
cleanup() {
local rc=$?
# remove temp artifacts; restore anything you changed
[[ -n "${tmpdir:-}" && -d "$tmpdir" ]] && rm -rf -- "$tmpdir"
return $rc
}
trap cleanup EXIT
on_err() {
local rc=$? line=$1
printf 'ERROR: line %s exited with status %s\n' "$line" "$rc" >&2
}
trap 'on_err "$LINENO"' ERRThe EXIT trap runs on normal exit, error exit (with -e), and most signals — making it the single reliable place to clean up. See templates/hardened-script.sh for the full pattern including signal-specific traps.
Safe temp files
tmpdir="$(mktemp -d)" # never hand-craft /tmp/$$ paths (race + predictable)
tmpfile="$(mktemp "$tmpdir/XXXXXX.json")"
# tmpdir is removed by the EXIT trap aboveNever use /tmp/myscript.$$ — predictable names are a symlink-attack vector and collide.
Input and dependency validation
require_cmd() {
command -v "$1" >/dev/null 2>&1 || { printf 'Missing dependency: %s\n' "$1" >&2; exit 127; }
}
require_cmd jq
require_cmd curl
: "${API_TOKEN:?API_TOKEN must be set}" # nounset-style guard for required env
if (( $# < 1 )); then
printf 'usage: %s <input-file>\n' "${0##*/}" >&2
exit 2
fiHardening checklist
#!/usr/bin/env bashshebangset -Eeuo pipefailandIFS=$'\n\t'- Every variable/command-substitution expansion is double-quoted
- Lists and argv built as arrays, expanded with
"${arr[@]}" EXITtrap cleans temp files;ERRtrap reports failures- Temp files via
mktemp/mktemp -d, removed in trap - Required commands checked with
command -v - Required args and env vars validated with clear usage + nonzero exit
--used before user-supplied paths inrm,cp, etc.- No
eval; no parsingls; no unquoted$(...) - Meaningful, distinct exit codes (2 usage, 127 missing dep, etc.)
shellcheckpasses clean (disables are justified inline)
Best Practices
- Make scripts re-runnable (idempotent). Guard mutations so a re-run after partial failure is safe.
- Separate config from logic. Read tunables from env with documented defaults:
: "${TIMEOUT:=30}". - Log to stderr, data to stdout. Keep stdout pure so the script composes in pipelines.
- Use functions with
localvariables; avoid global mutation. Declarelocalseparately from command substitution to avoid masking exit codes (local x; x="$(cmd)"). - Pin behavior, not the environment. Use full option names in comments; prefer
printfoverecho. - Fail with the right exit code. Reserve nonzero codes for distinct failure classes so callers can branch.
- Run ShellCheck in CI and treat it as a gate. See
references/shellcheck-codes.md.
Common Pitfalls
local x=$(cmd)swallows errors. Thelocalbuiltin's own success maskscmd's exit status even under-e. Split into two lines.-edoes not fire insideif/&&/||/!or the condition of a loop. Don't assume strict mode covers everything; check return codes explicitly there.cmd | while read ...runs the loop in a subshell — variables set inside are lost in older Bash. Use process substitutionwhile read ...; do ...; done < <(cmd)instead.set -e+ a function whose last command "fails" as a test silently disables errexit for that function's body. Avoid using such functions asifconditions when you also rely on-einside them.- Unquoted
$@vs"$@". Bare$@re-splits arguments; always"$@". readwithout-rmangles backslashes; alwaysread -r, and setIFS=per-read to preserve leading/trailing whitespace.- Predictable temp paths (
/tmp/$$) cause races and symlink attacks — alwaysmktemp. rm -rf "$dir/"*when$diris empty/unset can target/. Quote, validate, and use--; consider${dir:?}to abort on empty.
Other versions2 projects use a version of this.
Word for word · 2
- JayRHa/agent-skills★ 12100% same
- JayRHa/AgentSkills★ 12100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository194 other files it gives its agents.
- 0-templateSkill
- ab-test-analyzerSkill
- academy-guideSkill
- add-to-my-skillsSkill
- adr-authorSkill
- ai-tools-setupSkill
- algorithmic-artSkill
- api-and-interface-designSkill
- api-designerSkill
- api-docs-writerSkill
- apple-store-submitSkill
- aws-cost-optimizerSkill
- blog-post-writerSkill
- book-summarizerSkill
- branch-cleanupSkill
- brand-copy-landingSkill
- brand-copySkill
- brand-designSkill
- brand-guidelinesSkill
- browser-testing-with-devtoolsSkill
- canvas-designSkill
- changelog-generatorSkill
- changelog-keeperSkill
- chart-chooserSkill
- ci-cd-and-automationSkill
- ci-fix-loopSkill
- claude-apiSkill
- cloudflare-block-countriesSkill
- coderabbitloopSkill
- code-review-and-qualitySkill
- code-reviewerSkill
- code-simplificationSkill
- codexloopSkill
- comms-notionSkill
- comms-slackSkill
- comms-whatsappSkill
- competitive-analysisSkill
- concept-explainerSkill
- constraint-driven-developmentSkill
- context-engineeringSkill
- context-repoSkill
- cover-letter-writerSkill
- crash-courseSkill
- cron-schedulerSkill
- data-digestSkill
- data-pipeline-architectSkill
- debug-detectiveSkill
- debugging-and-error-recoverySkill
- decision-matrixSkill
- dependabot-triageSkill
- dependency-upgraderSkill
- deprecation-and-migrationSkill
- dev-instantdbSkill
- discernment-nudgeSkill
- doc-coauthoringSkill
- dockerfile-proSkill
- docs-index-keeperSkill
- documentation-and-adrsSkill
- docxSkill
- doubt-driven-developmentSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

