ia-linux-bash-scripting — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ia-linux-bash-scripting (Agent Skill) and scored it 91/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} is the classic direct prompt-injection phrasing. Placed in a skill body that the agent reads as trusted instructions, it tries to make the agent abandon its prior rules and follow whatever comes next — a full system-prompt override.
ignore/disregard/forget … previous instructions sentence.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Produce bash scripts that pass shellcheck --enable=all and shfmt -d with zero warnings.
Target: GNU Bash 4.4+ on Linux. No macOS/BSD workarounds, no Windows paths, no POSIX-only restrictions.
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s inherit_errexit
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
trap 'printf "Error at %s:%d\n" "${BASH_SOURCE[0]}" "$LINENO" >&2' ERR
trap 'rm -rf -- "${_tmpdir:-}"' EXIT-E propagates ERR traps into functionsinherit_errexit propagates errexit into $() command substitutions_tmpdir=$(mktemp -d)main() { ... } with source guard: [[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@" -- enables sourcing for testing"$var", "$(cmd)", "${array[@]}"local for function variables, local -r for function constants, readonly for script constantsprintf '%s\n' over echo -- predictable behavior, no flag interpretation[[ ]] for conditionals; (( )) for arithmetic; $() over backticks--: rm -rf -- "$path", grep -- "$pattern" "$file": "${VAR:?must be set}"eval user input; build commands as arrays: cmd=("grep" "--" "$pat" "$f"); "${cmd[@]}"local from assignment to preserve exit codes: local val; val=$(cmd)PS4='+${BASH_SOURCE[0]}:${LINENO}: ' with bash -x -- shows file:line per commandreadonly EX_USAGE=64 EX_CONFIG=78 -- no magic numbers in exit"${PIPESTATUS[@]}" shows exit code of each pipe stage, not just last failure# NUL-delimited file processing
while IFS= read -r -d '' f; do
process "$f"
done < <(find /path -type f -name '*.log' -print0)
# Array from command output
readarray -t lines < <(command)
readarray -d '' files < <(find . -print0)
# Glob with no-match guard
for f in *.txt; do [[ -e "$f" ]] || continue; process "$f"; doneverbose=false; output=""
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--verbose) verbose=true; shift ;;
-o|--output) output="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
--) shift; break ;;
-*) printf 'Unknown: %s\n' "$1" >&2; exit 1 ;;
*) break ;;
esac
doneDependency check:
require() { command -v "$1" &>/dev/null || { printf 'Missing: %s\n' "$1" >&2; exit 1; }; }
require jq; require curlDry-run wrapper:
run() { if [[ "${DRY_RUN:-}" == "1" ]]; then printf '[dry] %s\n' "$*" >&2; else "$@"; fi; }
run cp "$src" "$dst"Atomic file write -- write to temp, rename into place:
atomic_write() { local tmp; tmp=$(mktemp); cat >"$tmp"; mv -- "$tmp" "$1"; }
generate_config | atomic_write /etc/app/config.ymlRetry with backoff:
retry() { local n=0 max=5 delay=1; until "$@"; do ((++n>=max)) && return 1; sleep $delay; ((delay*=2)); done; }
retry curl -fsSL "$url"Script locking -- prevent concurrent runs:
exec 9>/var/lock/"${0##*/}".lock
flock -n 9 || { printf 'Already running\n' >&2; exit 1; }Idempotent operations -- safe to rerun:
ensure_dir() { [[ -d "$1" ]] || mkdir -p -- "$1"; }
ensure_link() { [[ -L "$2" ]] || ln -s -- "$1" "$2"; }Input validation: [[ "$1" =~ ^[1-9][0-9]*$ ]] || die "Invalid: $1" -- validate at script boundaries with [[ =~ ]]
umask 077 for scripts creating sensitive filestrap 'cleanup; exit 130' INT TERM -- preserves correct exit codes for callerslog() { printf '[%s] [%s] %s\n' "$(date -Iseconds)" "$1" "${*:2}" >&2; }
info() { log INFO "$@"; }
warn() { log WARN "$@"; }
error() { log ERROR "$@"; }
die() { error "$@"; exit 1; }| Bad | Fix | ||
|---|---|---|---|
for f in $(ls) | for f in *; do or `find -print0 \ | while read` | |
local x=$(cmd) | local x; x=$(cmd) -- preserves exit code | ||
x=$(cmd) then an [[ -z $x ]] fallback check | `x=$(cmd) \ | \ | true -- under set -e a failed $() in a bare assignment aborts the script there, so the fallback never runs (opposite of the local case: local` masks the failure, a bare assignment propagates it) |
echo "$data" | printf '%s\n' "$data" | ||
| `cat file \ | grep` | grep pat file | |
kill -9 $pid first | kill "$pid" first, -9 as last resort | ||
cd dir; cmd | `cd dir | exit 1 or subshell (cd dir && cmd)` |
${path%/*} not dirname, ${path##*/} not basename, ${var//old/new} not sed(( )) over expr; [[ =~ ]] over echo | grepval=$(cmd) once, reuse $valxargs -0 -P "$(nproc)" for parallel workdeclare -A map for lookups instead of repeated grep${var@Q} shell-quoted, ${var@U} uppercase, ${var@L} lowercasedeclare -n ref=varname nameref for indirect accesswait -n wait for any background job$EPOCHSECONDS, $EPOCHREALTIME -- timestamps without forking datesed -i (no '' suffix), grep -P (PCRE support), readlink -f (canonical path)timeout 30s cmd to prevent automation hangsRun shellcheck --enable=all script.sh. Key rules:
cd dir || exit${BASH_REMATCH[n]} not $n for regex capturesPre-commit: shellcheck *.sh && shfmt -i 2 -ci -d *.sh
Run shellcheck --enable=all and shfmt -d with zero warnings before declaring done. Test edge cases: empty input, missing files, spaces in paths.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.