Environment Variables and Secrets — Never in Code
Python's boolean evaluation treats non-empty strings as "truthy," regardless of their content. Imagine a switch: if a string is present, the switch is "on." To correctly interpret "False," you need a separate parser that explicitly translates specific string values ("true", "false", "1", "0") into actual boolean True or False.
The Setup
You want to protect database migrations or debug settings by setting environment variables. You use Python's built-in os.getenv to toggle a debug mode, but the app behaves unexpectedly.
What Does This Print?
import os
# The environment variable is set to "False" (string) in production config
os.environ["ENABLE_DEBUG"] = "False"
# Developer attempts to check if debug mode is active
debug_flag = os.getenv("ENABLE_DEBUG", False)
if debug_flag:
print("Result: SECURITY HOLE! Debug mode is active in production.")
else:
print("Result: Secure production mode configured successfully.")
The Output
The string "False" is a non-empty sequence in Python. In boolean evaluations, any non-empty string resolves to True. Because OS-level environment variables are always strings, reading "False" from the environment and passing it to a conditional block triggers the development-mode code path instead of the production path.
Why Python Does This
Python resolves strings using its built-in boolean evaluation rules: any string with a length greater than zero (i.e., bool("False")) is evaluated as truthy. Only an empty string "" or an explicit boolean object False evaluates to falsy. Since the system environment space represents variables solely as char-arrays (strings), reading from os.environ always yields strings. To parse config safe from type-casting holes, you must check the string against expected patterns, convert it to lowercase, or use a robust configuration parser like pydantic-settings to properly coerce the configurations.
The Fix
import os
# Fix: Compare the raw string environment variable to truthy values explicitly
raw_val = os.getenv("ENABLE_DEBUG", "false").lower()
# Explicit string checking avoids evaluating "False" as True
debug_flag = raw_val in ("true", "1", "yes")
if debug_flag:
print("Result: SECURITY HOLE! Debug mode is active in production.")
else:
print("Result: Secure production mode configured successfully.")
Explicitly parsing environment variable strings into boolean types ensures that the actual boolean value is used, rather than relying on Python's truthiness rules for strings. This prevents strings like "False" from being interpreted as True and avoids unintended behavior, especially for security-critical flags.
How This Fails in Real Systems
A fintech application exposed diagnostic endpoints and visual stack traces to public visitors. An operator attempted to disable debugging by defining DEBUG_MODE=False in their Helm chart. Because the system interpreted the string "False" as truthy, debug routes remained active, exposing database transaction queries to malicious users for two days.