Security
Security in Python means protecting secrets, validating input, and following safe coding practices.
Never Store Secrets in Code
Secrets include: API keys, passwords, tokens, database connection strings.
# BAD — secret in code
API_KEY = "sk-abc123secret456"
# GOOD — secret from environment
import os
API_KEY = os.environ["API_KEY"]
Use Environment Variables
Setting Variables
# In terminal
export API_KEY="sk-abc123secret456"
export DB_HOST="localhost"
Reading Variables in Python
import os
api_key = os.environ.get("API_KEY", "")
db_host = os.environ.get("DB_HOST", "localhost")
if not api_key:
raise ValueError("API_KEY environment variable is required")
Using .env Files
# .env file (NEVER commit to Git!)
API_KEY=sk-abc123secret456
DB_HOST=localhost
DB_PORT=5432
# Use pydantic-settings to load .env
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
api_key: str
db_host: str = "localhost"
db_port: int = 5432
model_config = {"env_file": ".env"}
settings = Settings()
Add .env to .gitignore
Never commit .env files to Git. They contain real secrets.
Validate All External Input
Never trust data from users, APIs, or files:
from pydantic import BaseModel, field_validator
class UserInput(BaseModel):
name: str
email: str
age: int
@field_validator("age")
@classmethod
def validate_age(cls, v: int) -> int:
if v < 0 or v > 150:
raise ValueError("Age must be between 0 and 150")
return v
@field_validator("email")
@classmethod
def validate_email(cls, v: str) -> str:
if "@" not in v:
raise ValueError("Invalid email address")
return v
Dependency Security
Keep Dependencies Updated
uv lock --upgrade
Check for Known Vulnerabilities
uv add --dev pip-audit
uv run pip-audit
Safe File Handling
from pathlib import Path
def read_config(file_path: str) -> str:
path = Path(file_path).resolve()
# Prevent path traversal attacks
allowed_dir = Path("/app/config").resolve()
if not str(path).startswith(str(allowed_dir)):
raise ValueError("Access denied: path outside allowed directory")
return path.read_text(encoding="utf-8")
Security Checklist
| Check | How |
|---|---|
| No secrets in code | Grep for API keys, passwords |
| .env in .gitignore | Check .gitignore file |
| Input validated | Use Pydantic models |
| Dependencies scanned | Run pip-audit |
| No SQL injection | Use parameterized queries |
| HTTPS only | Check all URLs start with https:// |
| Errors do not leak data | Check error messages |
Best Practices
- Never hardcode secrets — use environment variables
- Always validate external input (API data, user input, file content)
- Use Pydantic for data validation
- Use
pydantic-settingsfor configuration management - Add
.envto.gitignore - Audit dependencies for known vulnerabilities regularly
- Follow least privilege — give minimum permissions needed
- Log security events (failed logins, invalid tokens)