Shebang bash security

If you’ve written bash scripts, you’ve probably used a shebang line at the top.
But which one should you use: #!/bin/bash or #!/usr/bin/env bash?
And is there really a security risk with the latter?

The Two Approaches

Hardcoded Path: #!/bin/bash

This shebang assumes bash is installed at /bin/bash. It’s direct and predictable—you know exactly which interpreter will run your script.

Pros:

  • Predictable execution path
  • Works consistently on most Linux distributions
  • Slightly faster (no PATH lookup needed)

Cons:

  • Not portable to systems where bash lives elsewhere
  • Fails on some BSD systems or custom installations
  • Doesn’t allow users to specify an alternative bash version

PATH Lookup: #!/usr/bin/env bash

This shebang uses the env command to search for bash in your PATH environment variable, executing the first match it finds.

Pros:

  • Highly portable across different Unix-like systems
  • Allows users to override with their preferred bash version
  • Works regardless of where bash is installed

Cons:

  • Behavior depends on the user’s PATH
  • Potential security concern in specific scenarios

The Security Question

The security concern revolves around PATH injection attacks. If an attacker can manipulate the PATH environment variable before your script runs, #!/usr/bin/env bash could execute a malicious binary instead of the legitimate bash shell.

Here’s how such an attack might work:

# Attacker creates a fake bash
echo '#!/bin/sh' > /tmp/bash
echo 'malicious code here' >> /tmp/bash
chmod +x /tmp/bash

# Attacker modifies PATH
export PATH=/tmp:$PATH

# Now #!/usr/bin/env bash will find the fake bash first
./your-script.sh

When This Actually Matters

The security risk is real but contextual. It matters in these scenarios:

  1. Setuid/setgid scripts - Scripts running with elevated privileges
  2. System services - Scripts executed by systemd, init, or other system processes
  3. Cron jobs - Especially those running as root with potentially untrusted PATH
  4. CGI scripts - Web-accessible scripts where PATH might be influenced by requests
  5. Scripts processing untrusted input - Where an attacker has some control over the environment

When This Doesn’t Matter

For most use cases, the risk is negligible:

  • Regular user scripts run in a normal shell
  • Development scripts on your local machine
  • Scripts where you control the entire execution environment
  • Modern Linux systems with proper user privilege separation

If an attacker can already manipulate your PATH variable, you likely have a compromised environment where this is the least of your worries.

Best Practices

Here’s my recommendation based on the use case:

Use #!/usr/bin/env bash when:

  • Writing portable scripts meant to run on different systems
  • Creating open-source tools or utilities
  • Writing scripts for development or personal use
  • Portability is more important than the minimal security edge case

Use #!/bin/bash when:

  • Writing system administration scripts for specific infrastructure
  • Creating scripts that will run with elevated privileges
  • You need absolute predictability about which bash version runs
  • Security is paramount and you control the target systems

Never use shell scripts for:

  • Setuid binaries—use compiled programs instead
  • Security-critical operations requiring privilege escalation
  • Anything where the stakes of compromise are high

The Verdict

For most developers writing most scripts, #!/usr/bin/env bash is the right choice. The portability benefits far outweigh the theoretical security risk in typical use cases.

The security concern, while valid in principle, is often overstated. If you’re writing system-level scripts or anything running with elevated privileges, use #!/bin/bash and ensure proper environment sanitization. Better yet, use a compiled language for security-critical tasks.

Remember: security is about threat modeling. Understand your environment, know your attack surface, and choose accordingly. For your average bash script, being able to run it on any Unix-like system without modification is probably more valuable than defending against an already-compromised PATH.

my DevOps Odyssey

“Σα βγεις στον πηγαιμό για την Ιθάκη, να εύχεσαι να ‘ναι μακρύς ο δρόμος, γεμάτος περιπέτειες, γεμάτος γνώσεις.” - Kavafis’ Ithaka.