How to Enable Ruff Security Rules
Ruff’s S rule group implements flake8-bandit security checks, catching hardcoded passwords, injection vulnerabilities, insecure hashing, and unsafe deserialization before they reach production.
Enable the Full Set
Add the S group to the project’s pyproject.toml:
[tool.ruff.lint]
extend-select = [
"S", # flake8-bandit security rules
]This enables all flake8-bandit rules at once. Run the linter to see what it finds:
uv run ruff check .Pick Specific Rules
For a more targeted approach, enable individual rules instead of the full group:
[tool.ruff.lint]
extend-select = [
"S105", # Hardcoded passwords in strings
"S106", # Hardcoded passwords in function arguments
"S107", # Hardcoded passwords in function defaults
"S108", # Insecure temp file usage
"S113", # HTTP requests without timeout
"S301", # Pickle deserialization
"S324", # Insecure hash functions
"S608", # SQL injection via string formatting
]These rules can be combined with the recommended Ruff defaults by adding them to the same extend-select list.
| Rule | Category | What it catches |
|---|---|---|
| S105, S106, S107 | Secrets | Hardcoded passwords in assignments, arguments, and defaults |
| S108 | File safety | Insecure use of temp files |
| S113 | Network | HTTP requests missing a timeout parameter |
| S301 | Deserialization | Use of pickle.loads and related functions |
| S324 | Cryptography | Insecure hash algorithms like MD5 and SHA1 |
| S608 | Injection | SQL queries built with string concatenation or formatting |
Examples
Hardcoded secrets and insecure hashing
import hashlib
# S105: Possible hardcoded password assigned to: "password"
password = "supersecret123"
# S324: Probable use of insecure hash functions in `hashlib`: `md5`
digest = hashlib.md5(b"data").hexdigest()Fix by loading secrets from environment variables and switching to a secure hash algorithm:
import hashlib
import os
password = os.environ["APP_PASSWORD"]
digest = hashlib.sha256(b"data").hexdigest()SQL injection
# S608: Possible SQL injection vector through string-based query construction
def get_user(user_id):
query = "SELECT * FROM users WHERE id = " + user_id
return queryFix by using parameterized queries:
def get_user(cursor, user_id):
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
return cursor.fetchone()Suppress False Positives
Some S rules flag code that is safe in context. Use # noqa comments to suppress individual lines:
assert response.status_code == 200 # noqa: S101For broader suppression, use per-file ignores in pyproject.toml. This is common for test files, where assert statements (S101) and hardcoded test credentials (S105, S106) are expected:
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S101", "S105", "S106"]Learn More
Get Python tooling updates
Subscribe to the newsletter