Bird
Raised Fist0
Bash Scriptingscripting~15 mins

Script security best practices in Bash Scripting - Deep Dive

Choose your learning style10 modes available
Overview - Script security best practices
What is it?
Script security best practices are guidelines and techniques to write shell scripts that protect your system and data from accidental or malicious harm. These practices help prevent unauthorized access, data leaks, and unintended commands. They include careful handling of inputs, permissions, and environment settings to keep scripts safe and reliable.
Why it matters
Without script security, scripts can become a gateway for attackers or cause accidental damage by running harmful commands or exposing sensitive data. This can lead to data loss, system compromise, or downtime. Secure scripting protects your computer and network, ensuring scripts do only what you intend and nothing more.
Where it fits
Before learning script security, you should know basic shell scripting commands and how scripts run in a Unix-like environment. After mastering security best practices, you can explore advanced topics like secure automation, system hardening, and auditing scripts for vulnerabilities.
Mental Model
Core Idea
Secure scripting means writing scripts that trust nothing from outside and control what they do to avoid harm.
Think of it like...
It's like locking your house doors and checking who comes in before opening, so no strangers can enter and cause trouble.
┌───────────────────────────────┐
│         Script Security       │
├──────────────┬────────────────┤
│ Input Checks │ Permissions    │
├──────────────┼────────────────┤
│ Environment  │ Error Handling │
└──────────────┴────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstand script permissions basics
🤔
Concept: Learn how file permissions affect who can run or edit a script.
In Unix-like systems, scripts have permissions that control reading, writing, and executing. Use 'ls -l script.sh' to see permissions. The 'chmod' command changes them. For example, 'chmod 700 script.sh' means only the owner can read, write, and execute the script.
Result
The script becomes accessible only to the owner, reducing risk of unauthorized changes or execution.
Knowing permissions helps prevent others from running or modifying your script, which is a basic security layer.
2
FoundationAvoid running scripts as root unnecessarily
🤔
Concept: Understand the risks of running scripts with full system privileges.
Running scripts as root means they can change anything on the system. If the script has bugs or is tricked by bad input, it can cause serious damage. Always run scripts with the least privileges needed. Use 'sudo' only when absolutely necessary.
Result
Scripts run with limited power, reducing the chance of accidental or malicious system damage.
Limiting privileges minimizes the impact of mistakes or attacks inside scripts.
3
IntermediateSanitize all user inputs carefully
🤔Before reading on: do you think scripts should trust user inputs as-is or always check them? Commit to your answer.
Concept: Learn to check and clean inputs to prevent harmful commands or data from entering the script.
User inputs can contain dangerous characters or commands. Always validate inputs by checking their format, length, and allowed characters. For example, use regex or case statements to allow only expected values. Avoid using inputs directly in commands without checks.
Result
The script rejects or safely handles bad inputs, preventing injection attacks or crashes.
Input sanitization is key to stopping attackers from tricking your script into running harmful commands.
4
IntermediateUse absolute paths for commands and files
🤔Before reading on: do you think using just command names (like 'ls') is safe, or should scripts use full paths (like '/bin/ls')? Commit to your answer.
Concept: Avoid ambiguity by specifying exact locations of commands and files.
Scripts run commands based on the PATH environment variable, which can be changed by attackers to run malicious programs. Using absolute paths like '/bin/ls' ensures the intended command runs. Similarly, specify full file paths to avoid confusion or accidental overwrites.
Result
The script runs the correct commands and accesses the right files, reducing risk of hijacking.
Absolute paths prevent attackers from substituting commands or files with harmful versions.
5
IntermediateSet safe environment variables explicitly
🤔
Concept: Control the environment your script runs in to avoid unexpected behavior.
Environment variables like PATH, IFS, or LANG affect how scripts run. Attackers can manipulate these to change script behavior. At the start of your script, set variables like 'PATH=/usr/bin:/bin' and 'IFS=$'\n\t'' to safe values. Avoid inheriting unsafe environments.
Result
The script runs in a predictable environment, reducing surprises or exploits.
Explicit environment settings block attackers from influencing script execution through environment tricks.
6
AdvancedHandle errors and unexpected states robustly
🤔Before reading on: do you think ignoring errors in scripts is safe, or should scripts detect and respond to errors? Commit to your answer.
Concept: Make scripts detect failures and stop or recover safely instead of continuing blindly.
Use 'set -e' to make scripts exit on errors. Check command exit codes with 'if' statements. Use traps to clean up temporary files or reset states on exit. This prevents scripts from running dangerous commands after a failure or leaving the system in a bad state.
Result
Scripts fail safely and predictably, avoiding cascading problems or security holes.
Error handling prevents scripts from causing damage when something goes wrong.
7
ExpertAvoid code injection by careful command construction
🤔Before reading on: do you think building commands by concatenating strings with user input is safe, or risky? Commit to your answer.
Concept: Understand how attackers exploit command construction to run arbitrary code and how to prevent it.
Never build commands by directly inserting user input into strings. Instead, use arrays or separate arguments. For example, use 'command "$input"' instead of 'command $input'. This prevents attackers from injecting extra commands or options. Also, avoid 'eval' unless absolutely necessary and safe.
Result
Scripts resist injection attacks that could run harmful commands.
Knowing how shell parses commands helps you write scripts that attackers cannot trick into running bad code.
Under the Hood
When a bash script runs, the shell reads commands line by line, expanding variables and interpreting special characters. If inputs are not sanitized, malicious content can alter command structure or environment variables, causing unintended commands to execute. Permissions control who can read or run the script file, enforced by the operating system kernel. Environment variables influence command lookup and script behavior, so attackers can manipulate them to hijack execution.
Why designed this way?
Bash and Unix shells were designed for flexibility and power, allowing users to combine commands easily. This openness means scripts can be powerful but also vulnerable if not carefully written. Security practices evolved to add guardrails without losing flexibility, balancing usability and protection. Alternatives like restricted shells exist but limit functionality, so best practices focus on careful scripting.
┌───────────────┐
│   User Input  │
└──────┬────────┘
       │
┌──────▼────────┐
│  Script Parser │
│  (expands vars)│
└──────┬────────┘
       │
┌──────▼────────┐
│ Command Runner│
│ (executes cmd)│
└──────┬────────┘
       │
┌──────▼────────┐
│  OS Permissions│
│  & Environment │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Is it safe to trust environment variables in scripts by default? Commit to yes or no.
Common Belief:Environment variables are always safe and can be trusted inside scripts.
Tap to reveal reality
Reality:Environment variables can be changed by users or attackers to alter script behavior or command lookup.
Why it matters:Trusting environment variables blindly can let attackers run malicious commands or bypass security checks.
Quick: Does running a script as root always mean it is safe and secure? Commit to yes or no.
Common Belief:Running scripts as root is safe because root has all permissions.
Tap to reveal reality
Reality:Running as root increases risk because any bug or malicious input can cause system-wide damage.
Why it matters:Scripts running as root can accidentally delete files or open security holes if not carefully controlled.
Quick: Can you safely build shell commands by concatenating user input strings? Commit to yes or no.
Common Belief:Concatenating user input into commands is fine if you trust the input source.
Tap to reveal reality
Reality:Concatenation without sanitization allows code injection, letting attackers run arbitrary commands.
Why it matters:This leads to serious security breaches, including data theft or system compromise.
Quick: Is it okay to ignore error codes in scripts and continue running? Commit to yes or no.
Common Belief:Ignoring errors is fine; scripts will fix themselves or errors don't matter much.
Tap to reveal reality
Reality:Ignoring errors can cause scripts to run dangerous commands or leave the system in an unstable state.
Why it matters:This can cause data loss, security holes, or unpredictable system behavior.
Expert Zone
1
Scripts can be vulnerable to subtle race conditions when checking file permissions and then acting on files; understanding atomic operations helps prevent this.
2
Using shell builtins instead of external commands reduces risk of command hijacking and improves performance.
3
Beware of locale and character encoding issues that can affect input validation and command parsing in subtle ways.
When NOT to use
Avoid complex security logic inside bash scripts for critical systems; use dedicated security tools or languages with stronger typing and sandboxing like Python or Go. For very sensitive automation, consider compiled languages or containerized environments.
Production Patterns
In production, scripts often run with restricted user accounts, use logging and auditing, sanitize inputs from environment variables or files, and include fail-safe error handling. They also avoid 'eval' and use configuration files with strict permissions.
Connections
Principle of Least Privilege
Script security applies this principle by limiting script permissions and execution rights.
Understanding least privilege helps you design scripts that minimize damage if compromised.
Input Validation in Web Security
Both require sanitizing inputs to prevent injection attacks.
Knowing input validation in web apps clarifies why scripts must never trust user input blindly.
Locking Mechanisms in Physical Security
Just as locks control access to physical spaces, permissions and environment controls restrict script access and behavior.
This cross-domain view shows security is about controlling trust and access, whether digital or physical.
Common Pitfalls
#1Running scripts with world-writable permissions.
Wrong approach:chmod 777 script.sh
Correct approach:chmod 700 script.sh
Root cause:Misunderstanding that open permissions make scripts easier to use, ignoring security risks.
#2Using user input directly in commands without checks.
Wrong approach:rm -rf $user_input
Correct approach:if [[ "$user_input" =~ ^[a-zA-Z0-9_-]+$ ]]; then rm -rf "$user_input"; else echo 'Invalid input'; fi
Root cause:Not validating inputs leads to command injection vulnerabilities.
#3Relying on relative paths and default PATH environment.
Wrong approach:ls -l $file_path
Correct approach:/bin/ls -l /absolute/path/to/file
Root cause:Assuming environment variables and current directory are safe and unchanged.
Key Takeaways
Always limit who can read, write, or execute your scripts by setting strict permissions.
Never run scripts as root unless absolutely necessary to reduce risk of system damage.
Sanitize and validate all inputs to prevent attackers from injecting harmful commands.
Use absolute paths and set safe environment variables to avoid command hijacking.
Handle errors carefully to ensure scripts fail safely and do not cause unintended harm.

Practice

(1/5)
1. Which of the following is a key reason to use set -euo pipefail at the start of a bash script?
easy
A. It automatically logs all commands to a file for debugging.
B. It speeds up the script execution by running commands in parallel.
C. It stops the script immediately if any command fails or if an unset variable is used.
D. It disables all user inputs to prevent accidental changes.

Solution

  1. Step 1: Understand what set -euo pipefail does

    This command combination makes the script exit if any command fails (-e), if an unset variable is used (-u), and if any part of a pipeline fails (pipefail).
  2. Step 2: Identify the effect on script safety

    By stopping early on errors or unset variables, it prevents the script from continuing in an unexpected or unsafe state.
  3. Final Answer:

    It stops the script immediately if any command fails or if an unset variable is used. -> Option C
  4. Quick Check:

    Strict mode = stops on errors [OK]
Hint: Remember: strict mode stops on errors and unset variables [OK]
Common Mistakes:
  • Thinking it speeds up script execution
  • Assuming it logs commands automatically
  • Believing it disables user input
2. Which of the following is the correct way to check if a variable user_input is set and not empty in bash?
easy
A. if [ $user_input = "" ]; then echo "Empty"; fi
B. if [ -z "$user_input" ]; then echo "Empty"; fi
C. if [ -n $user_input ]; then echo "Empty"; fi
D. if [ "$user_input" == null ]; then echo "Empty"; fi

Solution

  1. Step 1: Understand the test for empty string

    The test [ -z "$user_input" ] returns true if the variable is unset or empty, which is the correct way to check emptiness safely.
  2. Step 2: Check other options for correctness

    if [ "$user_input" == null ]; then echo "Empty"; fi compares to 'null' string which is incorrect. if [ -n $user_input ]; then echo "Empty"; fi lacks quotes and reverses logic. if [ $user_input = "" ]; then echo "Empty"; fi lacks quotes and can cause errors if variable is unset.
  3. Final Answer:

    if [ -z "$user_input" ]; then echo "Empty"; fi -> Option B
  4. Quick Check:

    Use -z with quotes to check empty safely [OK]
Hint: Use quotes and -z to check empty variables safely [OK]
Common Mistakes:
  • Not quoting variables causing errors
  • Comparing to 'null' string instead of empty
  • Using wrong test operators
3. What will be the output of this script snippet if PATH is not set and set -u is enabled?
#!/bin/bash
set -u
echo "Path is: $PATH"
medium
A. No output, script runs silently
B. Path is:
C. Path is: /usr/bin:/bin
D. bash: PATH: unbound variable

Solution

  1. Step 1: Understand set -u effect

    The set -u option causes the script to exit with an error if an unset variable is referenced.
  2. Step 2: Analyze the script behavior

    Since PATH is not set, referencing $PATH triggers an unbound variable error and the script stops with a message.
  3. Final Answer:

    bash: PATH: unbound variable -> Option D
  4. Quick Check:

    Unset variable with set -u causes error [OK]
Hint: set -u errors on unset variables immediately [OK]
Common Mistakes:
  • Assuming empty string output instead of error
  • Thinking script runs silently
  • Assuming default PATH value is used
4. Identify the security issue in this script snippet:
#!/bin/bash
read -p "Enter filename: " file
cat $file
medium
A. Using read without validation allows command injection.
B. No issue, script is safe as is.
C. Missing quotes around $file causes syntax error.
D. Using cat is insecure; should use less instead.

Solution

  1. Step 1: Analyze input handling

    The script reads user input directly into file and uses it without validation or sanitization.
  2. Step 2: Understand risk of command injection

    If the user inputs something like file.txt; rm -rf /, the shell will execute the dangerous command, causing security risk.
  3. Final Answer:

    Using read without validation allows command injection. -> Option A
  4. Quick Check:

    Unvalidated input risks command injection [OK]
Hint: Always validate or sanitize user input before use [OK]
Common Mistakes:
  • Ignoring input validation
  • Thinking missing quotes cause syntax error here
  • Believing command choice alone fixes injection
5. You want to securely run a script that uses a password stored in a file. Which practice improves security best?
hard
A. Read the password from a file with restricted permissions and never echo it.
B. Store the password in plain text in the script for easy access.
C. Pass the password as a command line argument to the script.
D. Write the password to a temporary file with world-readable permissions.

Solution

  1. Step 1: Evaluate password storage methods

    Storing passwords in plain text inside scripts or passing them as command line arguments exposes them to other users or logs.
  2. Step 2: Choose secure handling

    Reading the password from a file with strict permissions (e.g., 600) and avoiding printing it prevents leaks and unauthorized access.
  3. Final Answer:

    Read the password from a file with restricted permissions and never echo it. -> Option A
  4. Quick Check:

    Restrict file permissions and avoid exposing secrets [OK]
Hint: Never expose passwords; restrict file access and avoid echoing [OK]
Common Mistakes:
  • Hardcoding passwords in scripts
  • Passing secrets as command line arguments
  • Using world-readable temporary files
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard