Chapter 11: Security Practices in Bash¶
Learning Objectives¶
By the end of this chapter, you will be able to:
- Implement safe input handling to minimize security risks
- Avoid common pitfalls like code injection and command substitution attacks
- Use sandboxing techniques and the principle of least privilege
- Protect sensitive data like credentials and API keys
- Securely manage file permissions, temporary files, and logs
- Apply macOS-specific security recommendations for Bash scripts
Introduction: Why Security Matters in Bash¶
Bash is powerful — but with great power comes great responsibility. Scripts often run with elevated privileges, handle sensitive data, or automate system-level tasks. A small oversight can lead to significant vulnerabilities. This chapter teaches practical strategies to write safer Bash scripts on macOS.
11.1 Safe Script Settings¶
Start your secure scripts with set -euo pipefail:
-e: Exit immediately if any command fails-u: Treat unset variables as an error-o pipefail: Prevents errors in pipelines from being masked
This ensures your script stops on unexpected issues.
11.2 Safe Input Handling¶
User input is one of the most common attack vectors. Malicious input can lead to command injection, file overwrite, or privilege escalation.
Best Practices:
- Always quote variables to prevent word splitting and glob expansion.
- Use
read -rto prevent backslash escapes.
- Validate and sanitize input. Use regex or
casestatements.
# Example: Validate a username
if [[ "$USERNAME" =~ ^[a-zA-Z0-9_-]{3,16}$ ]]; then
echo "Valid username"
else
echo "Invalid username"
exit 1
fi
Note: You can adjust your validation regex to be stricter if needed — for example, requiring usernames to start and end with an alphanumeric character.
- Avoid using
evalwhenever possible. It’s dangerous!
11.3 Avoiding Code Injection¶
Command injection happens when untrusted data is executed as part of a command.
Guidelines:
- Don’t
evalorexecuser-supplied input. - Use
--to mark the end of options:
- Prefer built-in tools that can handle edge cases safely (e.g.,
xargs -0withfind -print0).
11.4 Secure Storage: Avoid Plaintext Credentials¶
Never store passwords or API keys directly in your scripts. Instead:
- Use the macOS Keychain:
- Use environment variables and
.envfiles with secure permissions (chmod 600). - For deployment, use secure vaults or configuration management tools.
11.5 Secure File Permissions and Ownership¶
Ensure your scripts are not world-writable or executable by unauthorized users.
# Recommended permissions for sensitive scripts
chmod 700 myscript.sh
# Recommended permissions for sensitive data files
chmod 600 secrets.env
11.6 Script Sandboxing and Least Privilege¶
Minimize the impact if your script is exploited:
- Run scripts as a dedicated user with limited privileges.
- Use
sudoonly for commands that absolutely require it — and never run an entire script withsudoby default. - Use macOS sandboxing where appropriate, like
sandbox-exec.
11.7 Managing Temporary Files Securely¶
Temporary files are often a target for attackers.
- Use
mktempto create unique temp files:
- Store temp files in directories with restricted permissions.
11.8 Secure Logging Practices¶
Logging is essential — but don’t leak secrets:
- Avoid logging passwords, tokens, or API keys.
- Mask or truncate sensitive output if necessary.
- Set appropriate permissions on log files.
Consider using a helper function for logging with timestamps to improve traceability:
11.9 Handling Signals and Cleanup¶
Use trap to clean up securely on exit or interruption:
This ensures sensitive temp files don’t persist if your script is killed unexpectedly.
11.10 Example: A Secure Wrapper Script¶
Below is a simple example that ties all these practices together.
#!/bin/bash
set -euo pipefail
#
# Helper function to log messages with timestamp
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $*"
}
# Create secure log file
LOG_FILE="secure_script.log"
touch "$LOG_FILE"
chmod 600 "$LOG_FILE"
exec > >(tee -a "$LOG_FILE") 2>&1
log "Starting secure script..."
#
# Safe input: Username must start/end with alphanumeric, can contain dot, underscore, hyphen in between
read -rp "Enter your username: " USERNAME
if [[ ! "$USERNAME" =~ ^[a-zA-Z0-9]([a-zA-Z0-9._-]{1,14}[a-zA-Z0-9])?$ ]]; then
log "Invalid username!"
exit 1
fi
log "Username '$USERNAME' validated successfully."
#
# Retrieve password securely from Keychain
log "Attempting to retrieve password from Keychain for service 'MyService'."
PASSWORD=$(security find-generic-password -a "$USERNAME" -s "MyService" -w 2>/dev/null) || {
log "Failed to get password from Keychain."
exit 1
}
log "Password retrieved successfully."
#
# Secure temp file creation
TEMP_FILE=$(mktemp) || exit 1
log "Created secure temp file at $TEMP_FILE."
#
# Trap to clean up temp file on exit, interrupt, or termination
cleanup() {
if [[ -n "${TEMP_FILE:-}" && -f "$TEMP_FILE" ]]; then
log "Cleaning up temp file: $TEMP_FILE"
rm -f "$TEMP_FILE"
log "Temp file removed."
fi
}
trap cleanup EXIT INT TERM
#
# Do some secure work
log "Working securely... writing sensitive temp data."
echo "Sensitive temp data" > "$TEMP_FILE"
#
# Simulate more secure actions
log "Hello, $USERNAME! Your secure work is complete."
#
# Done
log "Script completed successfully."
11.11 macOS-Specific Security Considerations¶
- Leverage Keychain, System Integrity Protection (SIP), and Gatekeeper when distributing scripts.
- Consider using launchd to run privileged tasks securely.
- Always test scripts in a non-production environment with SIP enabled.
Chapter 11 Exercise¶
Secure Script Challenge¶
Write a Bash script that:
- Takes a filename as input and safely deletes it if it exists and the user confirms.
- Uses
mktempto create a secure temp file for logging actions. - Traps signals and ensures all temp files are cleaned up.
- Retrieves an API key securely (simulate with an environment variable).
- Sets file permissions correctly on all outputs.
macOS Scripting Tips¶
- Always review your scripts for injection risks.
- Keep sensitive data out of your version control system.
- Apply the principle of least privilege — every time.