PyGuard supports inline suppression comments to handle false positives and intentional security patterns (like security tool code that contains vulnerability detection patterns).
eval("user_input") # pyguard: disable
some_code() # noqaeval("safe_literal") # pyguard: disable=CWE-95
password == "test" # noqa: CWE-208exec(code) # pyguard: disable=CWE-95,CWE-78-
Security Tool Code: Code that detects vulnerabilities but isn't itself vulnerable
# Detection pattern in security scanner - not actual vulnerable code if "eval(" in code: # pyguard: disable=CWE-95 report_vulnerability("Code Injection")
-
False Positives: When PyGuard incorrectly flags safe code
__author__ = "Jane Doe" # pyguard: disable=CWE-798
-
Test Code: Intentionally vulnerable code for testing
def test_sql_injection_detection(): vulnerable = f"SELECT * FROM users WHERE id = {user_id}" # pyguard: disable=CWE-89 assert scanner.detect(vulnerable)
-
Acceptable Trade-offs: When you've assessed the risk and decided it's acceptable
# Internal admin tool, input validated elsewhere result = subprocess.call(command) # pyguard: disable=CWE-78
-
Avoiding Real Security Issues: Don't suppress actual vulnerabilities
# BAD: This is a real security issue password = "hardcoded123" # pyguard: disable
-
Ignoring Code Quality: Don't suppress quality issues without refactoring
# BAD: Fix the complexity instead def complex_function(): # pyguard: disable=COMPLEXITY # 500 lines of spaghetti code...
-
Lazy Development: Don't suppress issues to avoid proper fixes
# BAD: Use parameterized queries instead query = f"SELECT * FROM {table}" # pyguard: disable
CWE-89: SQL InjectionCWE-78: Command InjectionCWE-22: Path TraversalCWE-79: Cross-Site Scripting (XSS)CWE-95: Code Injection (eval, exec)CWE-208: Timing AttackCWE-327: Weak CryptographyCWE-330: Insecure RandomCWE-502: Unsafe DeserializationCWE-798: Hardcoded Credentials
COMPLEXITY: High cyclomatic complexityLONG-METHOD: Method exceeds line limitMAGIC-NUMBER: Unnamed numeric literalDOCUMENTATION: Missing docstringERROR-HANDLING: Broad exception catching
-
Document Why: Add a comment explaining the suppression
# This is pattern matching code in a security scanner, not actual vulnerable code if "eval(" in source_code: # pyguard: disable=CWE-95 issues.append(SecurityIssue("Code Injection"))
-
Be Specific: Suppress only the specific rule, not all rules
# Good: Specific suppression password_check = pwd == user_input # pyguard: disable=CWE-208 # Bad: Generic suppression password_check = pwd == user_input # noqa
-
Regular Review: Periodically review suppressions to ensure they're still valid
# TODO: Review this suppression after refactoring - 2025-10-15 complex_code() # pyguard: disable=COMPLEXITY
-
Prefer Fixes: Only suppress when fixing isn't feasible or appropriate
# Better: Fix the issue cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,)) # Instead of suppressing # cursor.execute(f"SELECT * FROM users WHERE id = {user_id}") # pyguard: disable
To exclude entire files or directories from scanning, use pyguard.toml:
[security]
exclude_patterns = [
"*/tests/*",
"*/test_*.py",
"*_test.py",
"*/fixtures/*"
]PyGuard's # noqa comments are compatible with other Python tools:
- flake8
- pylint
- ruff
- mypy
Use # noqa for cross-tool compatibility, or # pyguard: disable for PyGuard-specific suppressions.
class SecurityScanner:
def detect_sql_injection(self, code: str):
"""Detect SQL injection patterns."""
# These are detection patterns, not vulnerable code
if "execute(" in code and "%" in code: # pyguard: disable=CWE-89
return SecurityIssue("SQL Injection")
if ".format(" in code and "SELECT" in code: # pyguard: disable=CWE-89
return SecurityIssue("SQL Injection")class TestSecurityScanner:
def test_detects_sql_injection(self):
"""Test SQL injection detection."""
# Intentionally vulnerable code for testing
vulnerable_code = '''
query = f"SELECT * FROM users WHERE id = {user_id}" # pyguard: disable=CWE-89
cursor.execute(query)
'''
scanner = SecurityScanner()
issues = scanner.analyze(vulnerable_code)
assert len(issues) > 0# ML hyperparameters are not magic numbers
LEARNING_RATE = 0.001 # pyguard: disable=MAGIC-NUMBER
BATCH_SIZE = 32 # pyguard: disable=MAGIC-NUMBER
EPOCHS = 100 # pyguard: disable=MAGIC-NUMBERIf you find a false positive that shouldn't require suppression, please:
- Document the pattern
- Open an issue on GitHub
- Provide a minimal reproduction example
- Suggest how detection should be improved
This helps improve PyGuard for everyone!