Skip to main content

Python Coding Violations

Cyclopt analyzes your Python code to identify coding and security violations. Each check below lists its Rule ID, a description, a severity, and its category.

tip

Use a check's Rule ID to silence a finding in code with a cyclopt-ignore comment, or to exclude it project-wide in the configuration file.


Not In Loop

Rule ID: E0103

Description: Break or continue keywords are used outside a loop

Label Label

Bad Example
def check_value(value):
if value > 10:
continue
print(value)


for i in range(3):
check_value(i)
Good Example
for i in range(3):
if i == 2:
continue
print(i)

Function Redefined

Rule ID: E0102

Description: A function / class / method is redefined

Label Label

Bad Example
def greet():
print('Hello')

def greet():
print('Hi again')
Good Example
def say_hello():
print('Hello')

def say_goodbye():
print('Goodbye')

Continue In Finally

Rule ID: E0116

Description: Emitted when the continue keyword is found inside a finally clause, which is a SyntaxError

Label Label

Bad Example
while running:
try:
pass
finally:
continue # [continue-in-finally]
Good Example
while running:
try:
pass
except KeyError:
pass
else:
continue

Abstract Class Instantiated

Rule ID: E0110

Description: An abstract class with abc.ABCMeta or abc.ABC as metaclass has abstract methods and is instantiated

Label Label

Bad Example
import abc

class Vehicle(abc.ABC):
@abc.abstractmethod
def start_engine(self):
pass

car = Vehicle() # [abstract-class-instantiated]
Good Example
import abc

class Vehicle(abc.ABC):
@abc.abstractmethod
def start_engine(self):
pass

class Car(Vehicle):
def start_engine(self):
print("Vroom")

car = Car()

Star Needs Assignment Target

Rule ID: E0114

Description: Can use starred expression only in assignment target. Emitted when a star expression is not used in an assignment target

Label Label

Bad Example
planets = *["Mercury", "Venus", "Earth"] # [star-needs-assignment-target]
Good Example
mercury, *rest_of_planets = ["Mercury", "Venus", "Earth"]

Duplicate Argument Name

Rule ID: E0108

Description: Duplicate argument names in function definitions are syntax errors

Label Label

Bad Example
def get_animals(dog, cat, dog): # [duplicate-argument-name]
pass
Good Example
def get_animals(dog, cat, bird):
pass

Return In Init

Rule ID: E0101

Description: Explicit return in __init__ Used when the special class method __init__ has an explicit return value. __init__ magic method is a constructor of an instance, so it should construct it but not return anything.

Label Label

Bad Example
class Multiply:
def __init__(self, x, y): # [return-in-init]
return x * y
Good Example
class Multiply:
def __init__(self, x, y) -> None:
self.product = x * y

Too Many Star Expressions

Rule ID: E0112

Description: More than one starred expression in assignment. Emitted when there are more than one starred expressions (*x) in an assignment. This is a SyntaxError

Label Label

Bad Example
*dogs, *cats = ["Labrador", "Poodle", "Sphynx"] # [too-many-star-expressions]
Good Example
*labrador_and_poodle, sphynx = ["Labrador", "Poodle", "Sphynx"]

Nonlocal And Global

Rule ID: E0115

Description: Emitted when a name is both nonlocal and global

Label Label

Bad Example
VALUE = 100

def update_value(new_value): # [nonlocal-and-global]
global VALUE
nonlocal VALUE
VALUE = new_value
print(f"Updated global value: {VALUE}")

update_value(200)
Good Example
VALUE = 100

def update_value(new_value):
global VALUE
VALUE = new_value
print(f"Updated global value: {VALUE}")

update_value(200)

Used Prior Global Declaration

Rule ID: E0118

Description: Emitted when a name is used prior a global declaration, which results in an error since Python 3.6. It can't be emitted when using Python < 3.6

Label Label

Bad Example
FRUIT = "apple"

def update_fruit():
print(FRUIT) # [used-prior-global-declaration]
global FRUIT
FRUIT = "orange"
Good Example
FRUIT = "apple"

def update_fruit():
global FRUIT
FRUIT = "banana"

Assignment Outside Function

Rule ID: E0104

Description: An assignment is found outside a function or method

Label Label

Bad Example
x = 5 # [assignment-outside-function]
Good Example
def assign_value():
x = 5

Return Arg In Generator

Rule ID: E0106

Description: A return statement with an argument is found in a generator function or method. It's allowed in Python >= 3.3 but wasn't allowed earlier.

Label Label

Good Example
def yield_items():
for item in ['a', 'b', 'c']:
yield item
return "Finished!" # This was not allowed in Python 3.3 and earlier.

Invalid Star Assignment Target

Rule ID: E0113

Description: Starred assignment target must be in a list or tuple. Error occurs when using a star expression in invalid contexts.

Label Label

Bad Example
*numbers = [1, 2, 3] # [invalid-star-assignment-target]
Good Example
numbers = [1, 2, 3]

Bad Reversed Sequence

Rule ID: E0111

Description: The argument passed to reversed() is not a sequence. This error occurs when a non-iterable type is passed to reversed().

Label Label

Bad Example
reversed(1234) # [bad-reversed-sequence]
Good Example
reversed([1, 2, 3, 4])

Nonexistent Operator

Rule ID: E0107

Description: Attempting to use C-style increment or decrement operators (++ or --), which are not valid in Python.

Label Label

Bad Example
x = 0

while x < 5:
print(x)
++x # [nonexistent-operator]
Good Example
x = 0

while x < 5:
print(x)
x += 1

Yield Outside Function

Rule ID: E0105

Description: A yield statement is found outside a function or method, which is invalid.

Label Label

Bad Example
for i in range(5):
yield i # [yield-outside-function]
Good Example
def range_yield():
for i in range(5):
yield i

Init Is Generator

Rule ID: E0100

Description: The special method __init__ is turned into a generator, which is incorrect. __init__ cannot contain yield.

Label Label

Bad Example
class Animal:
def __init__(self, names): # [init-is-generator]
yield from names

cat = Animal(["Tom", "Jerry"])
Good Example
class Animal:
def __init__(self, names):
self.names = names

def get_names(self):
yield from self.names

cat = Animal(["Tom", "Jerry"])
for name in cat.get_names():
pass

Misplaced Format Function

Rule ID: E0119

Description: The format() function is not called on a string object directly, causing an error.

Label Label

Bad Example
print('Hello {}').format('World') # [misplaced-format-function]
Good Example
print('Hello {}'.format('World'))

Nonlocal Without Binding

Rule ID: E0117

Description: Emitted when a nonlocal variable does not have an attached name somewhere in the parent scopes

Label Label

Bad Example
class Animal:
def get_sound(self):
nonlocal sounds # [nonlocal-without-binding]
Good Example
class Animal:
sounds = ["bark", "meow"]

def get_sound(self):
nonlocal sounds

Lost Exception

Rule ID: W0150

Description: A break or a return statement is found inside the finally clause of a try...finally block, the exceptions raised in the try clause will be silently swallowed instead of being re-raised

Label Label

Bad Example
class InfinityError(ArithmeticError):
def __init__(self):
uper().__init__("You can't reach infinity!")

def calculate_division(dividend: float, divisor: float) -> float:
try:
return dividend / divisor
except ArithmeticError as e:
raise InfinityError() from e
finally:
return float('inf') # [lost-exception]
Good Example
class InfinityError(ArithmeticError):
def __init__(self):
super().__init__("You can't reach infinity!")

def calculate_division(dividend: float, divisor: float) -> float:
try:
return dividend / divisor
except ArithmeticError as e:
raise InfinityError() from e

Assert On Tuple

Rule ID: W0199

Description: A call of assert on a tuple will always evaluate to true if the tuple is not empty, and will always evaluate to false if it is

Label Label

Bad Example
assert (42, None) # [assert-on-tuple]
Good Example
val1, val2 = (42, None)
assert val1
assert val2

Assert On String Literal

Rule ID: W0129

Description: When an assert statement has a string literal as its first argument, which will cause the assert to always pass

Label Label

Bad Example
def test_multiplication():
a = 4 * 5
assert "No MultiplicationError were raised" # [assert-on-string-literal]
Good Example
def test_multiplication():
a = 4 * 5
assert a == 20

Self Assigning Variable

Rule ID: W0127

Description: Emitted when we detect that a variable is assigned to itself

Label Label

Bad Example
temperature = 100
temperature = temperature # [self-assigning-variable]
Good Example
temperature = 100

Comparison With Callable

Rule ID: W0143

Description: This message is emitted when pylint detects that a comparison with a callable was made, which might suggest that some parenthesis were omitted, resulting in potential unwanted behavior

Label Label

Bad Example
def function_returning_a_number() -> int:
return 42


def is_forty_two(num: int = 21):
# 21 == <function function_returning_a_number at 0x7f343ff0a1f0>
return num == function_returning_a_number # [comparison-with-callable]
Good Example
def function_returning_a_number() -> int:
return 42

def is_forty_two(num: int = 21):
# 21 == 42
return num == function_returning_a_number()

Dangerous Default Value

Rule ID: W0102

Description: A mutable value as list or dictionary is detected in a default value for an argument

Label Label

Bad Example
def whats_in_the_bag(items=[]): # [dangerous-default-value]
items.append("book")
return items
Good Example
def whats_in_the_bag(items=None):
if items is None:
items = []
items.append("book")
return items

Duplicate Key

Rule ID: W0109

Description: A dictionary expression binds the same key multiple times

Label Label

Bad Example
exam_scores = {"English": 80, "Physics": 85, "English": 90} # [duplicate-key]
Good Example
exam_scores = {"English": 80, "Physics": 85, "Chemistry": 90}

Useless Else On Loop

Rule ID: W0120

Description: Loops should only have an else clause if they can exit early with a break statement, otherwise the statements under else should be on the same scope as the loop itself

Label Label

Bad Example
def find_positive_number(numbers):
for x in numbers:
if x > 0:
return x
else: # [useless-else-on-loop]
print("Did not find a positive number")
Good Example
def find_positive_number(numbers):
for x in numbers:
if x > 0:
return x
print("Did not find a positive number")

Expression Not Assigned

Rule ID: W0106

Description: An expression that is not a function call is assigned to nothing. Probably something else was intended

Label Label

Bad Example
float(3.14) == "3.14" # [expression-not-assigned]
Good Example
is_equal: bool = float(3.14) == "3.14"

Confusing With Statement

Rule ID: W0124

Description: Emitted when a with statement component returns multiple values and uses name binding with as only for a part of those values, as in with ctx() as a, b. This can be misleading, since it's not clear if the context manager returns a tuple or if the node without a name binding is another context manager

Label Label

Bad Example
with open("data.txt", "r") as f1, f2: # [confusing-with-statement]
pass
Good Example
with open("data.txt", "r", encoding="utf8") as f1:
with open("log.txt", "w", encoding="utf8") as f2:
pass

Unnecessary Lambda

Rule ID: W0108

Description: The body of a lambda expression is a function call on the same argument list as the lambda itself. Such lambda expressions are in all but a few cases replaceable with the function being called in the body of the lambda

Label Label

Bad Example
df.map(lambda x: x.upper()) # [unnecessary-lambda]
Good Example
df.map(str.upper)

Assign To New Keyword

Rule ID: W0111

Description: async and await are reserved Python keywords in Python >= 3.6 versions

Label Label


Redeclared Assigned Name

Rule ID: W0128

Description: Emitted when we detect that a variable was redeclared in the same assignment

Label Label

Bad Example
ITEM, ITEM = ('apple', 'banana') # [redeclared-assigned-name]
Good Example
ITEM1, ITEM2 = ('apple', 'banana')

Pointless Statement

Rule ID: W0104

Description: A statement doesn't have (or at least seems to) any effect

Label Label

Bad Example
[4, 5, 6] # [pointless-statement]
Good Example
NUMS = [4, 5, 6]
print(NUMS)

Pointless String Statement

Rule ID: W0105

Description: A string is used as a statement (which of course has no effect). This is a particular case of W0104 with its own message so you can easily disable it if you're using those strings as documentation, instead of comments

Label Label

Bad Example
"""Function to calculate sum"""
"""Another pointless string statement""" # [pointless-string-statement]
Good Example
"""Function to calculate sum"""
# A comment explaining the logic used in summing.

Unnecessary Pass

Rule ID: W0107

Description: A pass statement that can be avoided is encountered

Label Label

Bad Example
class ValidationError(Exception):
"""This exception is raised for invalid inputs."""

pass # [unnecessary-pass]
Good Example
class ValidationError(Exception):
"""This exception is raised for invalid inputs."""

Unreachable

Rule ID: W0101

Description: There is some code behind a return or raise statement, which will never be accessed

Label Label

Bad Example
def greet_user():
return True
print("Welcome!") # [unreachable]
Good Example
def greet_user():
print("Welcome!")
return True

Eval Used

Rule ID: W0123

Description: You use the eval function, to discourage its usage. Consider using ast.literal_eval for safely evaluating strings containing Python expressions from untrusted sources

Label Label

Bad Example
eval("{1: 'a', 2: 'b'}") # [eval-used]
Good Example
from ast import literal_eval
literal_eval("{1: 'a', 2: 'b'}")

Exec Used

Rule ID: W0122

Description: You use the exec statement (function for Python 3), to discourage its usage. That doesn't mean you cannot use it! It's dangerous to use this function for a user input

Label Label

Bad Example
user_input = "John"
code = f"""eval(input('Execute this code, {user_input}: '))"""
result = exec(code) # [exec-used]
exec(result) # [exec-used]
Good Example
def get_user_input(name):
return input(f"Enter code for execution, {name}: ")

user_input = "John"
allowed_globals = {"__builtins__": None}
allowed_locals = {"print": print}
# pylint: disable-next=exec-used
exec(get_user_input(user_input), allowed_globals, allowed_locals)

Using Constant Test

Rule ID: W0125

Description: Emitted when a conditional statement (If or ternary if) uses a constant value for its test

Label Label

Bad Example
if False: # [using-constant-test]
print("Will never run.")
if True: # [using-constant-test]
print("Will always run.")
Good Example
print("This statement is executed.")

Missing Parentheses For Call In Test

Rule ID: W0126

Description: Emitted when a conditional statement (If or ternary if) seems to wrongly call a function due to missing parentheses

Label Label

Bad Example
import random

def is_sunny():
return random.choice([True, False])

if is_sunny: # [missing-parentheses-for-call-in-test]
print("It is sunny!")
Good Example
import random

def is_sunny():
return random.choice([True, False])

if is_sunny():
print("It is sunny!")

Literal Comparison

Rule ID: R0123

Description: Comparing an object to a literal, which is usually what you do not want to do, since you can compare to a different literal than what was expected altogether

Label Label

Bad Example
def is_a_banana(fruit):
return fruit is "banana" # [literal-comparison]
Good Example
def is_a_banana(fruit):
return fruit == "banana"

Comparison With Itself

Rule ID: R0124

Description: Something is compared against itself

Label Label

Bad Example
def is_a_banana(fruit):
a_banana = "banana"
return fruit == fruit # [comparison-with-itself]
Good Example
def is_a_banana(fruit):
a_banana = "banana"
return a_banana == fruit

Non Ascii Name

Rule ID: C0144

Description: Name contains at least one non-ASCII unicode character

Label Label


Invalid Name

Rule ID: C0103

Description: The name doesn't conform to naming rules associated to its type (constant, variable, class...)

Label Label

Bad Example
class dog: # [invalid-name]
def Bark(self, NUMBER_OF_BARK): # [invalid-name, invalid-name]
print("Bark" * NUMBER_OF_BARK)
return NUMBER_OF_BARK

Dog = dog().Bark(10) # [invalid-name]
Good Example
class Dog:
def bark(self, number_of_bark):
print("Bark" * number_of_bark)
return number_of_bark

DOG = Dog().bark(10)

Blacklisted Name

Rule ID: C0102

Description: The name is listed in the black list (unauthorized names)

Label Label


Singleton Comparison

Rule ID: C0121

Description: An expression is compared to singleton values like True, False or None

Label Label

Bad Example
lights_on = False
if lights_on == False: # [singleton-comparison]
print("Lights are off.")
Good Example
lights_on = False
if not lights_on:
print("Lights are off.")

Misplaced Comparison Constant

Rule ID: C0122

Description: The constant is placed on the left side of a comparison. It is usually clearer in intent to place it in the right hand side of the comparison

Label Label


Empty Docstring

Rule ID: C0112

Description: A module, function, class or method has an empty docstring (it would be too easy)

Label Label

Bad Example
def bar(): # [empty-docstring]
""""""
Good Example
def bar():
"""A simple function."""

Missing Class Docstring

Rule ID: C0115

Description: A class has no docstring. Even an empty class must have a docstring

Label Label

Bad Example
class Car: # [missing-class-docstring]
def __init__(self, make, model):
self.make = make
self.model = model
Good Example
class Car:
"""Class representing a car"""

def __init__(self, make, model):
self.make = make
self.model = model

Missing Function Docstring

Rule ID: C0116

Description: Missing function or method docstring used when a function or method has no docstring. Some special methods like __init__, protected, private functions, setters and deleters do not require a docstring. It's a good practice to describe what a function does for other programmers

Label Label

Bad Example
import os

def list_files(): # [missing-function-docstring]
print(os.listdir())
Good Example
import os

def list_files():
"""Function listing files in the current directory."""
print(os.listdir())

Missing Module Docstring

Rule ID: C0114

Description: A module has no docstring. Empty modules do not require a docstring

Label Label

Bad Example
import json # [missing-module-docstring]

def parse_json(data):
return json.loads(data)
Good Example
"""Module providing a function for parsing JSON data."""

import json

def parse_json(data):
return json.loads(data)

Unidiomatic Typecheck

Rule ID: C0123

Description: Using type() instead of isinstance() for a type check. The idiomatic way to perform an explicit type check in Python is to use isinstance(x, y) rather than type(x) == Y, type(x) is Y. Though there are unusual situations where these give different results

Label Label

Bad Example
data = [1, 2, 3]
if type(data) is list: # [unidiomatic-typecheck]
pass
Good Example
data = [1, 2, 3]
if isinstance(data, list):
pass

Access Member Before Definition

Rule ID: E0203

Description: An instance member is accessed before it's actually assigned

Label Label

Bad Example
class Robot:
def __init__(self, power_level):
if self.power_level > 100: # [access-member-before-definition]
print("Power Overload!")
self.power_level = power_level
Good Example
class Robot:
def __init__(self, power_level):
self.power_level = power_level
if self.power_level > 100:
print("Power Overload!")

Method Hidden

Rule ID: E0202

Description: A class defines a method which is hidden by an instance attribute from an ancestor class or set by some client code

Label Label

Bad Example
class Plant:
def __init__(self, nutrients):
self.nutrients = nutrients

def nutrients(self): # [method-hidden]
pass
Good Example
class Plant:
def __init__(self, nutrients):
self.nutrients = nutrients

def water_supply(self):
pass

Assigning Non Slot

Rule ID: E0237

Description: Assigning to an attribute not defined in the class slots

Label Label

Bad Example
class Worker:
__slots__ = ("name")

def __init__(self, name, position):
self.name = name
self.position = position # [assigning-non-slot]
self.initialize()
Good Example
class Worker:
__slots__ = ("name", "position")

def __init__(self, name, position):
self.name = name
self.position = position
self.initialize()

Duplicate Bases

Rule ID: E0241

Description: A class has duplicate bases

Label Label

Bad Example
class Vehicle:
pass

class Bike(Vehicle, Vehicle): # [duplicate-bases]
pass
Good Example
class Vehicle:
pass

class Bike(Vehicle):
pass

class Truck(Vehicle):
pass

Inconsistent Mro

Rule ID: E0240

Description: A class has an inconsistent method resolution order

Label Label

Bad Example
class X:
pass

class Y(X):
pass

class Z(X, Y): # [inconsistent-mro]
pass
Good Example
class X:
pass

class Y(X):
pass

class Z(Y): # or 'Y, X' but not 'X, Y'
pass

Inherit Non Class

Rule ID: E0239

Description: A class inherits from something which is not a class

Label Label

Bad Example
class Animal(str): # [inherit-non-class]
pass
Good Example
class Animal:
def __str__(self):
pass

Invalid Slots

Rule ID: E0238

Description: An invalid __slots__ is found in class. Only a string, an iterable or a sequence is permitted

Label Label

Bad Example
class Vehicle: # [invalid-slots]
__slots__ = True
Good Example
class Vehicle:
__slots__ = ("make", "model")

Invalid Slots Object

Rule ID: E0236

Description: An invalid (non-string) object occurs in __slots__

Label Label

Bad Example
class Animal:
__slots__ = ("species", 5) # [invalid-slots-object]
Good Example
class Animal:
__slots__ = ("species", "breed")

No Method Argument

Rule ID: E0211

Description: A method which should have the bound instance as first argument has no argument defined

Label Label

Bad Example
class Dog:
def bark(): # [no-method-argument]
print("woof")
Good Example
class Dog:
def bark(self):
print("woof")

No Self Argument

Rule ID: E0213

Description: A method has an attribute different the "self" as first argument. This is considered as an error since this is a so common convention that you shouldn't break it!

Label Label

Bad Example
class Book:
def __init__(this, title): # [no-self-argument]
this.title = title
Good Example
class Book:
def __init__(self, title):
self.title = title

Unexpected Special Method Signature

Rule ID: E0302

Description: Emitted when a special method was defined with an invalid number of parameters. If it has too few or too many, it might not work at all

Label Label

Bad Example
class FileHandler:
def __enter__(self, filepath): # [unexpected-special-method-signature]
pass

def __exit__(self, exception): # [unexpected-special-method-signature]
pass
Good Example
class FileHandler:
def __enter__(self):
pass

def __exit__(self, exc_type, exc_value, traceback):
pass

Class Variable Slots Conflict

Rule ID: E0242

Description: A value in slots conflicts with a class variable, property or method

Label Label

Bad Example
class Robot:
# +1: [class-variable-slots-conflict]
__slots__ = ("model", "year", "shutdown")
model = None

def __init__(self, model, year):
self.model = model
self.year = year

@property
def year(self):
return self.year

def shutdown(self):
print("Shutting down...")
Good Example
class Robot:
__slots__ = ("_year", "model")

def __init__(self, model, year):
self._year = year
self.model = model

@property
def year(self):
return self._year

def shutdown(self):
print("Shutting down...")

Invalid Bool Returned

Rule ID: E0304

Description: bool does not return bool Used when a bool method returns something which is not a bool

Label Label

Bad Example
class LightSwitch:
"""__bool__ returns a string"""

def __bool__(self): # [invalid-bool-returned]
return "on"

Invalid Bytes Returned

Rule ID: E0308

Description: bytes does not return bytes Used when a bytes method returns something which is not bytes

Label Label

Bad Example
class DataPacket:
"""__bytes__ returns <type 'list'>"""

def __bytes__(self): # [invalid-bytes-returned]
return [1, 2, 3]
Good Example
class DataPacket:
"""__bytes__ returns <type 'bytes'>"""

def __bytes__(self):
return b"data"

Invalid Format Returned

Rule ID: E0311

Description: format does not return str Used when a format method returns something which is not a string

Label Label

Bad Example
class Temperature:
"""__format__ returns <type 'float'>"""

def __format__(self, format_spec): # [invalid-format-returned]
return 98.6
Good Example
class Temperature:
"""__format__ returns <type 'str'>"""

def __format__(self, format_spec):
return "98.6°F"

Invalid Getnewargs Returned

Rule ID: E0312

Description: getnewargs does not return a tuple. Used when a getnewargs method returns something which is not a tuple

Label Label

Bad Example
class CustomGetNewArgs:
"""__getnewargs__ returns a string"""

def __getnewargs__(self): # [invalid-getnewargs-returned]
return 'abc'
Good Example
class CustomGetNewArgs:
"""__getnewargs__ returns <type 'tuple'>"""

def __getnewargs__(self):
return ('abc', 'def')

Invalid Getnewargs Ex Returned

Rule ID: E0313

Description: getnewargs_ex does not return a tuple containing (tuple, dict). Used when a getnewargs_ex method returns something which is not of the form tuple(tuple, dict)

Label Label

Bad Example
class CustomGetNewArgsEx:
"""__getnewargs_ex__ returns tuple with incorrect argument types"""

def __getnewargs_ex__(self): # [invalid-getnewargs-ex-returned]
return (list('x'), set())
Good Example
class CustomGetNewArgsEx:
"""__getnewargs_ex__ returns <type 'tuple'>"""

def __getnewargs_ex__(self):
return ((1, 2), {'x': 'y'})

Invalid Hash Returned

Rule ID: E0309

Description: hash does not return an integer. Used when a hash method returns something which is not an integer

Label Label

Bad Example
class CustomHash:
"""__hash__ returns a list"""

def __hash__(self): # [invalid-hash-returned]
return [1, 2, 3]
Good Example
class CustomHash:
"""__hash__ returns an int"""

def __hash__(self):
return 123

Invalid Index Returned

Rule ID: E0305

Description: index does not return an integer. Used when an index method returns something which is not an integer

Label Label

Bad Example
class CustomIndex:
"""__index__ returns a float"""

def __index__(self): # [invalid-index-returned]
return 3.14
Good Example
class CustomIndex:
"""__index__ returns an int"""

def __index__(self):
return 42

Non Iterator Returned

Rule ID: E0301

Description: An __iter__ method returns something which is not an iterable (i.e., lacks a __next__ method)

Label Label

Bad Example
import random

class RandomItems:
def __init__(self, items):
self.items = items

def __iter__(self): # [non-iterator-returned]
self.idx = 0
return self

LIST_ITEMS = ['Apple', 'Banana', 'Grape']
for item in RandomItems(LIST_ITEMS):
print(item)
Good Example
import random

class RandomItems:
def __init__(self, items):
self.items = items

def __iter__(self):
self.idx = 0
return self

def __next__(self):
if self.idx == len(self.items):
raise StopIteration
self.idx += 1
return self.items[self.idx - 1]

LIST_ITEMS = ['Apple', 'Banana', 'Grape']
for item in RandomItems(LIST_ITEMS):
print(item)

Invalid Length Returned

Rule ID: E0303

Description: A __len__ method returns something that is not a non-negative integer

Label Label

Bad Example
class CustomSet:
def __init__(self, elements):
self.elements = {'a', 'b', 'c'}

def __len__(self): # [invalid-length-returned]
return -1
Good Example
class CustomSet:
def __init__(self, elements):
self.elements = {'a', 'b', 'c'}

def __len__(self):
return len(self.elements)

Invalid Length Hint Returned

Rule ID: E0310

Description: length_hint does not return a non-negative integer. Used when a length_hint method returns something that is not a non-negative integer

Label Label

Bad Example
class CustomLengthHint:
"""__length_hint__ returns a negative int"""

def __length_hint__(self): # [invalid-length-hint-returned]
return -5
Good Example
class CustomLengthHint:
"""__length_hint__ returns a non-negative int"""

def __length_hint__(self):
return 20

Invalid Repr Returned

Rule ID: E0306

Description: repr does not return str Used when a repr method returns something which is not a string

Label Label

Bad Example
class CustomRepr:
"""__repr__ returns <type 'float'>"""

def __repr__(self): # [invalid-repr-returned]
return 3.14
Good Example
class CustomRepr:
"""__repr__ returns <type 'str'>"""

def __repr__(self):
return "pi"

Invalid Str Returned

Rule ID: E0307

Description: str does not return str Used when a str method returns something which is not a string

Label Label

Bad Example
class CustomStr:
"""__str__ returns list"""

def __str__(self): # [invalid-str-returned]
return [1, 2, 3]
Good Example
class CustomStr:
"""__str__ returns <type 'str'>"""

def __str__(self):
return "apple pie"

Protected Access

Rule ID: W0212

Description: A protected member (i.e. class member with a name beginning with an underscore) is accessed outside the class or a descendant of the class where it's defined

Label Label

Bad Example
class Bird:
def __fly(self):
pass

jane = Bird()
jane.__fly() # [protected-access]
Good Example
class Bird:
def __fly(self):
pass

def soar(self):
return self.__fly()

jane = Bird()
jane.soar()

Attribute Defined Outside Init

Rule ID: W0201

Description: An instance attribute is defined outside the __init__ method

Label Label

Bad Example
class Employee:
def promote(self):
self.is_promoted = True # [attribute-defined-outside-init]
Good Example
class Employee:
def __init__(self):
self.is_promoted = False

def promote(self):
self.is_promoted = True

No Init

Rule ID: W0232

Description: A class has no __init__ method, neither its parent classes

Label Label

Bad Example
class Car:
def drive(self):
print('driving')
Good Example
class Car:
def __init__(self):
self.speed = 0

def drive(self):
print('driving')

Abstract Method

Rule ID: W0223

Description: An abstract method (i.e. raise NotImplementedError) is not overridden in concrete class

Label Label

Bad Example
import abc

class Vehicle:
@abc.abstractmethod
def start_engine(self):
pass

class Bike(Vehicle): # [abstract-method]
pass
Good Example
import abc

class Vehicle:
@abc.abstractmethod
def start_engine(self):
pass


class Bike(Vehicle):
def start_engine(self):
print("Vroom")

Invalid Overridden Method

Rule ID: W0236

Description: We detect that a method was overridden in a way that does not match its base class which could result in potential bugs at runtime

Label Label

Bad Example
class Tree:
async def grow(self, soil):
soil.enrich(self)

class Oak(Tree):
def grow(self, soil): # [invalid-overridden-method]
soil.enrich(self)
Good Example
class Tree:
async def grow(self, soil):
soil.enrich(self)

class Oak(Tree):
async def grow(self, soil):
soil.enrich(self)

Arguments Differ

Rule ID: W0221

Description: A method has a different number of arguments than in the implemented interface or in an overridden method

Label Label

Bad Example
class Sandwich:
def make(self, bread, filling):
return f'{bread} and {filling}'
Good Example
class BLTSandwich(Sandwich):
def make(self, bread, filling, bacon): # [arguments-differ]
return f'{bread}, {filling}, and {bacon}'

Signature Differs

Rule ID: W0222

Description: A method signature is different than in the implemented interface or in an overridden method

Label Label

Bad Example
class Vehicle:
def start(self, fuel=100):
print(f"Started with {fuel} units of fuel!")


class Car(Vehicle):
def start(self, fuel): # [signature-differs]
super(Vehicle, self).start(fuel)
print("Engine is now running!")
Good Example
class Vehicle:
def start(self, fuel=100):
print(f"Started with {fuel} units of fuel!")

class Car(Vehicle):
def start(self, fuel=100):
super(Vehicle, self).start(fuel)
print("Engine is now running!")

Bad Staticmethod Argument

Rule ID: W0211

Description: A static method has self or a value specified in valid-classmethod-first-arg option or valid-metaclass-classmethod-first-arg option as the first argument

Label Label

Bad Example
class Eagle:
@staticmethod
def fly(self): # [bad-staticmethod-argument]
pass
Good Example
class Eagle:
@staticmethod
def fly(height):
pass

Useless Super Delegation

Rule ID: W0235

Description: Used whenever we can detect that an overridden method is useless, relying on super() delegation to do the same thing as another method from the MRO

Label Label

Bad Example
class Bird:
def fly(self):
print("Flying")

class Sparrow(Bird):
def fly(self): # [useless-super-delegation]
super().fly()
print("Flying again")
Good Example
class Bird:
def fly(self):
print("Flying")

class Sparrow(Bird):
def fly(self):
print("Sparrow in flight")

Non Parent Init Called

Rule ID: W0233

Description: An __init__ method is called on a class which is not in the direct ancestors for the analysed class

Label Label

Bad Example
class Insect:
def __init__(self):
self.has_wings = True

class Butterfly(Insect):
def __init__(self):
super().__init__()
self.is_beautiful = True

class MonarchButterfly(Butterfly):
def __init__(self):
Insect.__init__(self) # [non-parent-init-called]
self.is_migratory = True
Good Example
class Insect:
def __init__(self):
self.has_wings = True

class Butterfly(Insect):
def __init__(self):
super().__init__()
self.is_beautiful = True

class MonarchButterfly(Butterfly):
def __init__(self):
super().__init__()
self.is_migratory = True

Super Init Not Called

Rule ID: W0231

Description: An ancestor class method has an __init__ method which is not called by a derived class

Label Label

Bad Example
class Tree:
def __init__(self, species="Tree"):
self.species = species
print(f"Planting a {self.species}")

class Oak(Tree):
def __init__(self): # [super-init-not-called]
print("Growing an oak tree")
Good Example
class Tree:
def __init__(self, species="Tree"):
self.species = species
print(f"Planting a {self.species}")


class Oak(Tree):
def __init__(self):
super().__init__("Oak")

Property With Parameters

Rule ID: R0206

Description: Detected that a property also has parameters, which are useless, given that properties cannot be called with additional arguments

Label Label

Bad Example
class Drill:
@property
def depth(self, value): # [property-with-parameters]
pass
Good Example
class Drill:
@property
def depth(self):
"""Property accessed with '.depth'."""
pass

def set_depth(value):
"""Function called with .set_depth(value)."""
pass

Useless Object Inheritance

Rule ID: R0205

Description: A class inherits from object, which under Python 3 is implicit, hence can be safely removed from bases

Label Label

Bad Example
class Plane(object): # [useless-object-inheritance]
...
Good Example
class Plane: ...

No Classmethod Decorator

Rule ID: R0202

Description: A class method is defined without using the decorator syntax

Label Label

Bad Example
class Flower:
COLORS = []

def __init__(self, color):
self.color = color

def set_colors(cls, *args):
"""classmethod to set flower colors"""
cls.COLORS = args

set_colors = classmethod(set_colors) # [no-classmethod-decorator]
Good Example
class Flower:
COLORS = []

def __init__(self, color):
self.color = color

@classmethod
def set_colors(cls, *args):
"""classmethod to set flower colors"""
cls.COLORS = args

No Staticmethod Decorator

Rule ID: R0203

Description: A static method is defined without using the decorator syntax

Label Label

Bad Example
class Mouse:
def run(self):
pass

run = staticmethod(run) # [no-staticmethod-decorator]
Good Example
class Mouse:
@staticmethod
def run(self):
pass

No Self Use

Rule ID: R0201

Description: A method doesn't use its bound instance, and so could be written as a function

Label Label

Bad Example
class Car:
def start_engine(self): # [no-self-use]
print('Engine started')
Good Example
def start_engine():
print('Engine started')

Single String Used For Slots

Rule ID: C0205

Description: A class __slots__ is a simple string, rather than an iterable

Label Label

Bad Example
class Tree: # [single-string-used-for-slots]
__slots__ = 'species'

def __init__(self, species):
self.species = species
Good Example
class Tree:
__slots__ = ('species',)

def __init__(self, species):
self.species = species

Bad Classmethod Argument

Rule ID: C0202

Description: A class method has a first argument named differently than the value specified in valid-classmethod-first-arg option (default to "cls"), recommended to easily differentiate them from regular instance methods

Label Label

Bad Example
class Vehicle:
@classmethod
def create(cls): # [bad-classmethod-argument]
return cls()
Good Example
class Vehicle:
@classmethod
def create(cls):
return cls()

Bad Mcs Classmethod Argument

Rule ID: C0204

Description: A metaclass class method has a first argument named differently than the value specified in valid-metaclass-classmethod-first-arg option (default to mcs), recommended to easily differentiate them from regular instance methods

Label Label

Bad Example
class Factory(type):
@classmethod
def make_product(thing): # [bad-mcs-classmethod-argument]
pass
Good Example
class Factory(type):
@classmethod
def make_product(mcs):
pass

Bad Mcs Method Argument

Rule ID: C0203

Description: A metaclass method has a first argument named differently than the value specified in valid-classmethod-first-arg option (default to cls), recommended to easily differentiate them from regular instance methods

Label Label

Bad Example
class Manager(type):
def assign_task(task): # [bad-mcs-method-argument]
pass
Good Example
class Manager(type):
def assign_task(cls):
pass

Method Check Failed

Rule ID: F0202

Description: Pylint has been unable to check methods signature compatibility for an unexpected reason. Please report this kind if you don't make sense of it

Label Label

Bad Example
class Device:
def start_device(self, config):
# [method-check-failed]
pass
Good Example
class Device:
def start_device(self, config):
pass

Too Few Public Methods

Rule ID: R0903

Description: Class has too few public methods, so be sure it's really worth it

Label Label

Bad Example
class Bird:
def __init__(self, species: str):
self.species = species

def fly(self):
print(f"The {self.species} is flying.")
Good Example
import dataclasses

@dataclasses.dataclass
class Bird:
species: str

def fly(bird: Bird):
print(f"The {bird.species} is flying.")

Too Many Ancestors

Rule ID: R0901

Description: Class has too many parent classes, try to reduce this to get a simpler (and so easier to use) class

Label Label

Bad Example
class Mammal: ...
class FlyingAnimal(Mammal): ...
class SwimmingAnimal(Mammal): ...
class EndangeredSpecies(Mammal): ...

# max of 7 by default, can be configured
class Bat( # [too-many-ancestors]
FlyingAnimal,
SwimmingAnimal,
EndangeredSpecies,
):
pass
Good Example
class Animal:
can_fly: bool
can_swim: bool
is_endangered: bool

class Mammal(Animal):
can_fly = False
can_swim = False
is_endangered = False

class Bat(Mammal):
can_fly = True
is_endangered = True

Too Many Arguments

Rule ID: R0913

Description: A function or method takes too many arguments

Label Label

Bad Example
def process_sensor_data( # [too-many-arguments]
accelerometer,
gyroscope,
magnetometer,
barometer,
proximity_sensor,
light_sensor,
current_time,
temperature_sensor,
):
pass
Good Example
from dataclasses import dataclass

@dataclass
class Sensor:
accelerometer: float
gyroscope: float
magnetometer: float
barometer: float

@dataclass
class EnvironmentSensor:
proximity: float
light: float
temperature: float

def process_sensor_data(
motion: Sensor,
environment: EnvironmentSensor,
current_time,
):
pass

Too Many Boolean Expressions

Rule ID: R0916

Description: An if statement contains too many boolean expressions

Label Label

Bad Example
def check_valid_triangle(a, b, c):
# +1: [too-many-boolean-expressions]
if (a > 0 and b > 0 and c > 0) and (a + b > c and a + c > b and b + c > a):
pass
Good Example
def check_valid_triangle(a, b, c):
if all(x > 0 for x in [a, b, c]) and (a + b > c and a + c > b and b + c > a):
pass

Too Many Branches

Rule ID: R0912

Description: A function or method has too many branches, making it hard to follow

Label Label

Bad Example
def map_day_to_word(day): # [too-many-branches]
if day == 1:
return 'Monday'
elif day == 2:
return 'Tuesday'
elif day == 3:
return 'Wednesday'
elif day == 4:
return 'Thursday'
elif day == 5:
return 'Friday'
elif day == 6:
return 'Saturday'
elif day == 7:
return 'Sunday'
else:
return None
Good Example
def map_day_to_word(day):
return {
1: 'Monday',
2: 'Tuesday',
3: 'Wednesday',
4: 'Thursday',
5: 'Friday',
6: 'Saturday',
7: 'Sunday',
}.get(day)

Too Many Instance Attributes

Rule ID: R0902

Description: Class has too many instance attributes, try to reduce this to get a simpler (and so easier to use) class

Label Label

Bad Example
class Car: # [too-many-instance-attributes]
def __init__(self):
self.make = 'Toyota'
self.model = 'Camry'
self.year = 2022
self.engine = 'V6'
self.transmission = 'Automatic'
self.color = 'Blue'
self.fuel_type = 'Gasoline'
self.seating_capacity = 5
self.mileage = 30000
Good Example
import dataclasses

@dataclasses.dataclass
class Engine:
engine_type: str
fuel_type: str

@dataclasses.dataclass
class Car:
make: str
model: str
year: int
engine: Engine
seating_capacity: int
mileage: int

car = Car(
make='Toyota', model='Camry', year=2022, engine=Engine('V6', 'Gasoline'), seating_capacity=5, mileage=30000
)

Too Many Locals

Rule ID: R0914

Description: A function or method has too many local variables

Label Label

Bad Example
def process_purchase_info(purchases): # [too-many-locals]
item_list = []
purchase_total = 0
discount = 0.1
shipping_cost = 5.99
tax = 0.07
final_total = 0
reward_points = 0
loyalty_bonus = 0.05
payment_method = 'Credit Card'
for item in purchases:
pass
Good Example
from typing import NamedTuple

class PurchaseDetails(NamedTuple):
purchase_total: float
discount: float
shipping_cost: float
tax: float

def process_purchase_info(purchases):
purchase_details = PurchaseDetails(100, 0.1, 5.99, 0.07)
final_total = _calculate_final_total(purchase_details)
_handle_rewards_and_loyalty(purchases, final_total)

def _calculate_final_total(details: PurchaseDetails):
# logic to calculate final total
pass

def _handle_rewards_and_loyalty(purchases, final_total):
# handle reward logic
pass

Too Many Public Methods

Rule ID: R0904

Description: Class has too many public methods, try to reduce this to get a simpler (and so easier to use) class

Label Label

Bad Example
class Game: # [too-many-public-methods]
def start(self): pass
def stop(self): pass
def reset(self): pass
def save(self): pass
def load(self): pass
def pause(self): pass
def resume(self): pass
def quit(self): pass
def restart(self): pass
def autosave(self): pass
Good Example
class GameController:
def __init__(self):
self.state = 'Stopped'

def start(self):
self.state = 'Running'

def stop(self):
self.state = 'Stopped'

def pause(self):
self.state = 'Paused'

class SaveSystem:
def save(self): pass
def load(self): pass

class Game:
def __init__(self):
self.controller = GameController()
self.save_system = SaveSystem()

Too Many Return Statements

Rule ID: R0911

Description: Function contains too many return statements

Label Label

Bad Example
def classify_grade(score):
if score >= 90:
return 'A'
elif score >= 80:
return 'B'
elif score >= 70:
return 'C'
elif score >= 60:
return 'D'
else:
return 'F'
Good Example
def classify_grade(score):
return next((grade for score_threshold, grade in [(90, 'A'), (80, 'B'), (70, 'C'), (60, 'D')] if score >= score_threshold), 'F')

Too Many Statements

Rule ID: R0915

Description: A function or method contains too many statements

Label Label

Bad Example
def initialize_game(): # [too-many-statements]
player = Player()
game = Game()
game.setup_board()
game.assign_pieces()
player.set_position(0, 0)
player.set_health(100)
player.set_inventory([])
enemy = Enemy()
enemy.set_position(10, 10)
enemy.set_health(100)
weapon = Weapon('sword')
armor = Armor('shield')
player.equip(weapon)
player.equip(armor)
game.start()
Good Example
def initialize_game():
player = _initialize_player()
enemy = _initialize_enemy()
game = _initialize_game_environment(player, enemy)
game.start()

def _initialize_player():
player = Player()
player.set_position(0, 0)
player.set_health(100)
player.set_inventory([])
player.equip(Weapon('sword'))
player.equip(Armor('shield'))
return player

def _initialize_enemy():
enemy = Enemy()
enemy.set_position(10, 10)
enemy.set_health(100)
return enemy

def _initialize_game_environment(player, enemy):
game = Game()
game.setup_board()
game.assign_pieces()
return game

Bad Except Order

Rule ID: E0701

Description: Except clauses are not in the correct order (from the more specific to the more generic). If you don't fix the order, some exceptions may not be caught by the most specific handler.

Label Label

Bad Example
try:
result = int(input('Enter a number: '))
except Exception:
print('An error occurred')
except ValueError: # [bad-except-order]
print('Invalid input')
Good Example
try:
result = int(input('Enter a number: '))
except ValueError:
print('Invalid input')
except Exception:
print('An error occurred')

Catching Non Exception

Rule ID: E0712

Description: A class which doesn't inherit from Exception is used as an exception in an except clause

Label Label

Bad Example
class BarError:
pass

try:
'abc' + 123
except BarError: # [catching-non-exception]
pass
Good Example
class BarError(Exception):
pass

try:
'abc' + 123
except BarError:
pass

Bad Exception Context

Rule ID: E0703

Description: Using the syntax raise ... from ..., where the exception context is not an exception, nor None. This message belongs to the exceptions checker

Label Label

Bad Example
try:
raise ValueError('Issue encountered') from 'Not an exception' # [bad-exception-context]
except ValueError:
pass
Good Example
try:
raise ValueError('Issue encountered') from KeyError('Wrong key')
except ValueError:
pass

Notimplemented Raised

Rule ID: E0711

Description: NotImplemented is raised instead of NotImplementedError

Label Label

Bad Example
class Bird:
def fly(self):
raise NotImplemented # [notimplemented-raised]
Good Example
class Bird:
def fly(self):
raise NotImplementedError

Raising Bad Type

Rule ID: E0702

Description: Something which is neither a class, an instance or a string is raised (i.e. a TypeError will be raised)

Label Label

Bad Example
class ImpossibleCalculationError(OverflowError):
def __init__(self):
super().__init__("Calculation exceeded the limits!")


def calculate_area(radius: float) -> float:
try:
return 3.14 * radius ** 2
except OverflowError as e:
raise None # [raising-bad-type]
Good Example
class ImpossibleCalculationError(OverflowError):
def __init__(self):
super().__init__("Calculation exceeded the limits!")

def calculate_area(radius: float) -> float:
try:
return 3.14 * radius ** 2
except OverflowError as e:
raise ImpossibleCalculationError() from e

Raising Non Exception

Rule ID: E0710

Description: A new style class which doesn't inherit from BaseException is raised

Label Label

Bad Example
raise list # [raising-non-exception]
Good Example
raise ValueError("Invalid operation!")

Misplaced Bare Raise

Rule ID: E0704

Description: A bare raise is not used inside an except clause. This generates an error, since there are no active exceptions to be reraised. An exception to this rule is represented by a bare raise inside a finally clause, which might work, as long as an exception is raised inside the try block, but it is nevertheless a code smell that must not be relied upon

Label Label

Bad Example
def validate_input(x):
if x == '':
raise # [misplaced-bare-raise]
Good Example
def validate_input(x):
if x == '':
raise ValueError(f"Input cannot be empty: {x}")

Duplicate Except

Rule ID: W0705

Description: An except catches a type that was already caught by a previous handler

Label Label

Bad Example
try:
1 + 'a'
except TypeError:
pass
except TypeError: # [duplicate-except]
pass
Good Example
try:
1 + 'a'
except TypeError:
pass

Broad Except

Rule ID: W0703

Description: An except catches a too general exception, possibly burying unrelated errors

Label Label

Bad Example
try:
1 / 0
except Exception: # [broad-except]
pass
Good Example
try:
1 / 0
except ZeroDivisionError: # handle specific error
pass

Raise Missing From

Rule ID: W0707

Description: Consider explicitly re-raising using the 'from' keyword. Python 3's exception chaining ensures the traceback shows both the current exception and the original one. Not using 'raise from' leads to an inaccurate traceback that might obscure the true source of the error.

Label Label

Bad Example
try:
open('non_existent_file.txt')
except FileNotFoundError as e:
raise IOError("File cannot be opened") # [raise-missing-from]
Good Example
try:
open('non_existent_file.txt')
except FileNotFoundError as e:
raise IOError("File cannot be opened") from e

Raising Format Tuple

Rule ID: W0715

Description: Passing multiple arguments to an exception constructor, with one of them being a tuple for string formatting, leads to incorrect behavior. Correct the formatting by using '%' operator inside the string.

Label Label

Bad Example
raise TypeError("Unsupported operand type(s) %s %s", ("int", "str")) # [raising-format-tuple]
Good Example
raise TypeError("Unsupported operand type(s) %s %s" % ("int", "str"))

Binary Op Exception

Rule ID: W0711

Description: Avoid using except A or B for catching exceptions. To catch multiple exceptions, use the tuple syntax: except (A, B).

Label Label

Bad Example
try:
int('abc')
except ValueError or TypeError: # [binary-op-exception]
pass
Good Example
try:
int('abc')
except (ValueError, TypeError):
pass

Wrong Exception Operation

Rule ID: W0716

Description: Binary operations between exceptions like ValueError + TypeError are invalid. Use a tuple (ValueError, TypeError) to catch multiple exceptions.

Label Label

Bad Example
try:
float('abc')
except ValueError + TypeError: # [wrong-exception-operation]
pass
Good Example
try:
float('abc')
except (ValueError, TypeError):
pass

Bare Except

Rule ID: W0702

Description: Avoid using bare except clauses, as they catch all exceptions and obscure the specific errors you're trying to handle.

Label Label

Bad Example
try:
open('non_existent_file.txt')
except: # [bare-except]
file = None
Good Example
try:
open('non_existent_file.txt')
except FileNotFoundError:
file = None

Try Except Raise

Rule ID: W0706

Description: Raising the same exception immediately after catching it (raise by itself) is redundant. Either raise a more detailed exception or remove the try-except block entirely.

Label Label

Bad Example
try:
int('invalid')
except ValueError as e: # [try-except-raise]
raise
Good Example
# Raise a more descriptive exception:
try:
int('invalid')
except ValueError as e:
raise TypeError("Input must be a valid integer") from e

Bad Indentation

Rule ID: W0311

Description: Improper indentation in Python is problematic, as it can lead to runtime errors. Ensure consistent indentation.

Label Label

Bad Example
if input():
print('yes') # [bad-indentation]
Good Example
if input():
print('yes')

Missing Final Newline

Rule ID: C0304

Description: The last line in a file is missing a newline

Label Label

Bad Example
open("file.txt") # CRLF
close("file.txt") # End-of-file (EOF)
# [missing-final-newline]
Good Example
open("file.txt")
close("file.txt")

# End-of-file (EOF)

Line Too Long

Rule ID: C0301

Description: A line is longer than a given number of characters

Label Label

Bad Example
# +1: [line-too-long]
PLANETS = ["mercury", "venus", "earth", "mars", "jupiter", "saturn", "uranus", "neptune"]
Good Example
PLANETS = [
"mercury",
"venus",
"earth",
"mars",
"jupiter",
"saturn",
"uranus",
"neptune",
]

Mixed Line Endings

Rule ID: C0327

Description: There are mixed (LF and CRLF) newline signs in a file

Label Label

Bad Example
read_file("file.txt") # CRLF
write_file("file.txt") # LF
# [mixed-line-endings]
Good Example
read_file("file.txt") # CRLF
write_file("file.txt") # CRLF

Multiple Statements

Rule ID: C0321

Description: More than one statement is found on the same line

Label Label

Bad Example
animals = ["cat", "dog", "parrot"]

if "cat" in animals: pass # [multiple-statements]
else:
print("no cats!")
Good Example
animals = ["cat", "dog", "parrot"]

if "cat" in animals:
pass
else:
print("no cats!")

Too Many Lines

Rule ID: C0302

Description: A module has too many lines, reducing its readability

Label Label

Bad Example
def calculate_sum(lst): # [too-many-lines]
sum = 0
for num in lst:
sum += num
return sum

def main():
print(calculate_sum([1, 2, 3]))
print(calculate_sum([10, 20, 30]))

Trailing Newlines

Rule ID: C0305

Description: There are trailing blank lines in a file

Label Label

Bad Example
print("banana")

# The file ends with 2 empty lines # +1: [trailing-newlines]
Good Example
print("banana")

Trailing Whitespace

Rule ID: C0303

Description: There is whitespace between the end of a line and the newline

Label Label

Bad Example
print("Goodbye")
# [trailing-whitespace] #
Good Example
print("Goodbye")

Unexpected Line Ending Format

Rule ID: C0328

Description: There is a different newline than expected

Label Label

Bad Example
print("I'm eating breakfast!") # CRLF
print("I'm eating lunch!") # CRLF
# [unexpected-line-ending-format]
Good Example
print("I'm eating breakfast!") # LF
print("I'm eating lunch!") # LF

Superfluous Parens

Rule ID: C0325

Description: A single item in parentheses follows an if, for, or other keyword

Label Label

Bad Example
name = input()
age = input()
if (name == age): # [superfluous-parens]
pass
Good Example
name = input()
age = input()
if name == age:
pass

Relative Beyond Top Level

Rule ID: E0402

Description: A relative import tries to access too many levels in the current package

Label Label

Bad Example
from ................galaxy import Star # [relative-beyond-top-level]
Good Example
from universe.galaxy import Star

Import Self

Rule ID: W0406

Description: A module is importing itself

Label Label

Bad Example
from my_module import function_name # [import-self]

def function_name():
pass

Preferred Module

Rule ID: W0407

Description: A module imported has a preferred replacement module. They are configured in .pylintrc or through CLI arguments

Label Label

Bad Example
import xmlrpc.client # [preferred-module]
Good Example
import http.client

Reimported

Rule ID: W0404

Description: A module is reimported multiple times

Label Label

Bad Example
import json
import json # [reimported]
Good Example
import json

Deprecated Module

Rule ID: W0402

Description: Used a module marked as deprecated is imported

Label Label

Bad Example
import imp # [deprecated-module]
Good Example
import importlib

Wildcard Import

Rule ID: W0401

Description: This is a bad practice because it clutters namespace with unneeded modules, packages, variables, etc. Moreover, it takes time to load them too

Label Label

Bad Example
from os import * # [wildcard-import]
Good Example
import os
from os.path import join, dirname

Misplaced Future

Rule ID: W0410

Description: Python 2.5 and greater require future import to be the first non-docstring statement in the module. This message belongs to the imports checker

Label Label

Bad Example
import time
from __future__ import division # [misplaced-future]
Good Example
from __future__ import division
import time

Cyclic Import

Rule ID: R0401

Description: A cyclic import between two or more modules is detected

Label Label

Bad Example
def add_numbers():
from .helper import add_two_numbers
return add_two_numbers() + 1
Good Example
def add_two_numbers():
return 2

def add_three_numbers():
return add_two_numbers() + 1

Wrong Import Order

Rule ID: C0411

Description: PEP8 import order is not respected (standard imports first, then third-party libraries, then local imports)

Label Label

Bad Example
import os
from . import tools
import sys # [wrong-import-order]
Good Example
import os
import sys
from . import tools

Wrong Import Position

Rule ID: C0413

Description: Code and imports are mixed

Label Label

Bad Example
import os
user_dir = os.getenv('USER')
import sys # [wrong-import-position]
Good Example
import os
import sys
user_dir = os.getenv('USER')

Useless Import Alias

Rule ID: C0414

Description: An import alias is the same as the original package (e.g., using import numpy as numpy instead of import numpy as np)

Label Label

Bad Example
import numpy as numpy # [useless-import-alias]
Good Example
import numpy as np

Import Outside Toplevel

Rule ID: C0415

Description: An import statement is used anywhere other than the module top-level. Move this import to the top of the file

Label Label

Bad Example
def get_version():
import platform
return platform.python_version()
Good Example
import platform

def get_version():
return platform.python_version()

Ungrouped Imports

Rule ID: C0412

Description: Imports are not grouped by packages

Label Label

Bad Example
import os
import sys
import json
import logging.config # [ungrouped-imports]
Good Example
import os
import sys
import logging.config
import json

Multiple Imports

Rule ID: C0410

Description: Import statement importing multiple modules is detected

Label Label

Bad Example
import os, sys # [multiple-imports]
Good Example
import os
import sys

Logging Format Truncated

Rule ID: E1201

Description: A logging statement format string terminates before the end of a conversion specifier

Label Label

Bad Example
import logging
logging.warning("Incorrect version: %", sys.version) # [logging-format-truncated]
Good Example
import logging
logging.warning("Python version: %s", sys.version)

Logging Too Few Args

Rule ID: E1206

Description: A logging format string is given too few arguments

Label Label

Bad Example
import logging
try:
function()
except Exception as e:
logging.error("%s error: %s", e) # [logging-too-few-args]
Good Example
import logging
try:
function()
except Exception as e:
logging.error("%s error: %s", type(e), e)

Logging Too Many Args

Rule ID: E1205

Description: A logging format string is given too many arguments

Label Label

Bad Example
import logging
try:
function()
except Exception as e:
logging.error("Error: %s", type(e), e) # [logging-too-many-args]
Good Example
import logging
try:
function()
except Exception as e:
logging.error("%s error: %s", type(e), e)

Logging Unsupported Format

Rule ID: E1200

Description: An unsupported format character is used in a logging statement format string

Label Label

Bad Example
import logging
logging.info("%s %y", "Hello", "World") # [logging-unsupported-format]
Good Example
import logging
logging.info("%s %s", "Hello", "World")

Logging Format Interpolation

Rule ID: W1202

Description: A logging statement uses a call form of logging.<logging method>(format_string.format(...)). It’s better to pass the parameters directly to the logging function instead

Label Label

Bad Example
logging.error("Version: {}".format(sys.version)) # [logging-format-interpolation]
Good Example
logging.error("Version: %s", sys.version)

Logging Fstring Interpolation

Rule ID: W1203

Description: A logging statement has a call form of logging.<logging method>(f"..."). Use another type of string formatting instead. You can use different formatting but leave interpolation to the logging function by passing the parameters as arguments. If logging-format-interpolation is disabled then you can use str.format. If logging-not-lazy is disabled then you can use certain formatting as normal

Label Label

Bad Example
import logging
import os

logging.warning(f"Current directory: {os.getcwd()}") # [logging-fstring-interpolation]
Good Example
import logging
import os

logging.warning("Current directory: %s", os.getcwd())

Logging Not Lazy

Rule ID: W1201

Description: A logging statement has a call form of logging.<logging method>(format_string % (format_args...)). Use another type of string formatting instead. You can use different formatting but leave interpolation to the logging function by passing the parameters as arguments. If logging-fstring-interpolation is disabled then you can use fstring formatting. If logging-format-interpolation is disabled then you can use str.format

Label Label

Bad Example
import logging

try:
connect_to_database()
except DatabaseError as e:
logging.error("Database connection failed: %s" % e) # [logging-not-lazy]
raise
Good Example
import logging

try:
connect_to_database()
except DatabaseError as e:
logging.error("Database connection failed: %s", e)
raise

Unpacking In Except

Rule ID: E1603

Description: Implicit unpacking of exceptions is not supported in Python 3 Python3 will not allow implicit unpacking of exceptions in except clauses. See https://www.python.org/dev/peps/pep-3110/

Label Label

Bad Example
try:
raise ValueError("An error occurred")
except ValueError, e: # Implicit unpacking (invalid in Python 3)
print(e)
Good Example
try:
raise ValueError("An error occurred")
except ValueError as e: # Explicit unpacking (valid in Python 3)
print(e)

Import Star Module Level

Rule ID: E1609

Description: Import * only allowed at module level Used when the import star syntax is used somewhere else than the module level. This message can't be emitted when using Python >= 3.0

Label Label

Bad Example
def my_function():
from math import * # Importing * inside a function (invalid)
Good Example
from math import * # Importing * at the module level (valid)

Non Ascii Bytes Literal

Rule ID: E1610

Description: Non-ascii bytes literals not supported in 3.x Used when non-ascii bytes literals are found in a program. They are no longer supported in Python 3. This message can't be emitted when using Python >= 3.0

Label Label

Bad Example
my_bytes = b"non-ASCII character: ü" # Non-ASCII byte literal (invalid in Python 3)
Good Example
my_string = "non-ASCII character: ü" # Use string literals for non-ASCII text

Parameter Unpacking

Rule ID: E1602

Description: Parameter unpacking specified Used when parameter unpacking is specified for a function(Python 3 doesn't allow it)

Label Label

Bad Example
exec 'print("Hello, world!")' # Python 2 style exec statement (invalid in Python 3)
Good Example
exec('print("Hello, world!")') # Use exec() function in Python 3

Long Suffix

Rule ID: E1606

Description: Use of long suffix Used when "l" or "L" is used to mark a long integer. This will not work in Python 3, since int and long types have merged. This message can't be emitted when using Python >= 3.0

Label Label

Bad Example
my_number = long(100) # long is not available in Python 3 (invalid)
Good Example
my_number = int(100) # Use int in Python 3

Old Octal Literal

Rule ID: E1608

Description: Use of old octal literal Used when encountering the old octal syntax, removed in Python 3. To use the new syntax, prepend 0o on the number. This message can't be emitted when using Python >= 3.0

Label Label

Bad Example
class MyClass: # Old-style class definition (Python 2)
pass
Good Example
class MyClass(object): # New-style class definition (Python 3)
pass

Old Ne Operator

Rule ID: E1607

Description: Use of the <> operator Used when the deprecated <> operator is used instead of "!=". This is removed in Python 3. This message can't be emitted when using Python >= 3.0

Label Label

Bad Example
if isinstance(my_var, basestring): # basestring is not available in Python 3
print("It's a string")
Good Example
if isinstance(my_var, str): # Use str instead in Python 3
print("It's a string")

Backtick

Rule ID: E1605

Description: Use of the operator Used when the deprecated "" (backtick) operator is used instead of the str() function

Label Label

Bad Example
if x <> y: # Python 2 style not-equal operator (invalid in Python 3)
print("x is not equal to y")
Good Example
if x != y: # Use != operator in Python 3
print("x is not equal to y")

Old Raise Syntax

Rule ID: E1604

Description: Use raise ErrorClass(args) instead of raise ErrorClass, args. Used when the alternate raise syntax 'raise foo, bar' is used instead of 'raise foo(bar)'

Label Label

Bad Example
print "my_var" # Backticks used for repr (invalid in Python 3)
Good Example
print(repr(my_var)) # Use repr() function instead

Print Statement

Rule ID: E1601

Description: print statement used Used when a print statement is used (print is a function in Python 3)

Label Label

Bad Example
print "Hello, world!" # Python 2 style print statement (invalid in Python 3)
Good Example
print("Hello, world!") # Python 3 print function

Deprecated Types Field

Rule ID: W1652

Description: Accessing a deprecated fields on the types module Used when accessing a field on types that has been removed in Python 3

Label Label

Bad Example
import types
my_type = types.SomeDeprecatedField # Deprecated field (invalid in Python 3)
Good Example
# Use an alternative valid type or method in Python 3

Deprecated Itertools Function

Rule ID: W1651

Description: Accessing a deprecated function on the itertools module Used when accessing a function on itertools that has been removed in Python 3

Label Label

Bad Example
import string # Let's assume "string" module is deprecated (hypothetical)
Good Example
import string_new # Import updated or alternative module

Deprecated String Function

Rule ID: W1649

Description: Accessing a deprecated function on the string module Used when accessing a string function that has been deprecated in Python 3

Label Label

Bad Example
import string
print(string.uppercase) # Deprecated in Python 3
Good Example
import string
print(string.ascii_uppercase) # Use ascii_uppercase in Python 3

Deprecated Operator Function

Rule ID: W1657

Description: Accessing a removed attribute on the operator module Used when accessing a field on operator module that has been removed in Python 3

Label Label

Bad Example
my_list = [1, 2, 3]
my_list.sort(lambda x: -x) # Deprecated way of sorting
Good Example
my_list = sorted(my_list, reverse=True) # Use sorted() with reverse

Deprecated Sys Function

Rule ID: W1660

Description: Accessing a removed attribute on the sys module Used when accessing a field on sys module that has been removed in Python 3

Label Label

Bad Example
my_iter = iter([1, 2, 3])
value = my_iter.next() # Use of ".next()" method (invalid in Python 3)
Good Example
value = next(my_iter) # Use "next()" function instead

Deprecated Urllib Function

Rule ID: W1658

Description: Accessing a removed attribute on the urllib module Used when accessing a field on urllib module that has been removed or moved in Python 3

Label Label

Bad Example
try:
risky_code()
except Exception, e: # Old-style exception handling (invalid in Python 3)
print(e)
Good Example
try:
risky_code()
except Exception as e: # Use Python 3 style exception handling
print(e)

Xreadlines Attribute

Rule ID: W1659

Description: Accessing a removed xreadlines attribute Used when accessing the xreadlines() function on a file stream, removed in Python 3

Label Label

Bad Example
import MyModule # Deprecated import
Good Example
from mymodule import new_functionality # Use updated import

Metaclass Assignment

Rule ID: W1623

Description: Assigning to a class's metaclass attribute Used when a metaclass is specified by assigning to metaclass (Python 3 specifies the metaclass as a class statement argument)

Label Label

Bad Example
my_list = [1, 2, 3]
print(my_list.has_key(2)) # Example: has_key() method is deprecated (invalid in Python 3)
Good Example
print(2 in my_list) # Use "in" operator instead of has_key()

Next Method Called

Rule ID: W1622

Description: Called a next() method on an object Used when an object's next() method is called (Python 3 uses the next() built-in function)

Label Label


Dict Iter Method

Rule ID: W1620

Description: Calling a dict.iter*() method Used for calls to dict.iterkeys(), itervalues() or iteritems() (Python 3 lacks these methods)

Label Label

Bad Example
my_dict = {"a": 1, "b": 2}
for key in my_dict.iterkeys(): # iterkeys() is removed in Python 3
print(key)
Good Example
my_dict = {"a": 1, "b": 2}
for key in my_dict.keys(): # Use keys() instead
print(key)

Dict View Method

Rule ID: W1621

Description: Calling a dict.view*() method Used for calls to dict.viewkeys(), viewvalues() or viewitems() (Python 3 lacks these methods)

Label Label

Bad Example
my_dict = {"a": 1, "b": 2}
print(my_dict.viewkeys()) # viewkeys() is removed in Python 3
Good Example
my_dict = {"a": 1, "b": 2}
print(my_dict.keys()) # Use keys() instead

Exception Message Attribute

Rule ID: W1645

Description: Exception.message removed in Python 3 Used when the message attribute is accessed on an Exception. Use str(exception) instead

Label Label

Bad Example
try:
raise Exception("An error occurred")
except Exception as e:
print(e.message) # Exception.message is removed in Python 3
Good Example
try:
raise Exception("An error occurred")
except Exception as e:
print(str(e)) # Use str() to access the error message

Eq Without Hash

Rule ID: W1641

Description: Implementing eq without also implementing hash Used when a class implements eq but not hash. In Python 2, objects get object.hash as the default implementation, in Python 3 objects get None as their default hash implementation if they also implement eq

Label Label

Bad Example
class Fruit: # [eq-without-hash]
def __init__(self) -> None:
self.name = "apple"
def __eq__(self, other: object) -> bool:
return isinstance(other, Fruit) and other.name == self.name
Good Example
class Fruit:
def __init__(self) -> None:
self.name = "apple"
def __eq__(self, other: object) -> bool:
return isinstance(other, Fruit) and other.name == self.name
def __hash__(self) -> int:
return hash(self.name)

Indexing Exception

Rule ID: W1624

Description: Indexing exceptions will not work on Python 3 Indexing exceptions will not work on Python 3. Use exception.args[index] instead

Label Label


Bad Python3 Import

Rule ID: W1648

Description: Module moved in Python 3 Used when importing a module that no longer exists in Python 3

Label Label


Raising String

Rule ID: W1625

Description: Raising a string exception Used when a string exception is raised. This will not work on Python 3

Label Label


Standarderror Builtin

Rule ID: W1611

Description: StandardError built-in referenced Used when the StandardError built-in function is referenced (missing from Python 3)

Label Label

Bad Example
try:
raise StandardError("An error occurred") # StandardError is removed in Python 3
except StandardError as e:
print(e)
Good Example
try:
raise Exception("An error occurred") # Use Exception instead
except Exception as e:
print(e)

Comprehension Escape

Rule ID: W1662

Description: Using a variable that was bound inside a comprehension Emitted when using a variable, that was bound in a comprehension handler, outside of the comprehension itself. On Python 3 these variables will be deleted outside of the comprehension

Label Label


Exception Escape

Rule ID: W1661

Description: Using an exception object that was bound by an except handler Emitted when using an exception, that was bound in an except handler, outside of the except handler. On Python 3 these exceptions will be deleted once they get out of the except handler

Label Label


Deprecated Str Translate Call

Rule ID: W1650

Description: Using str.translate with deprecated deletechars parameters Used when using the deprecated deletechars parameters from str.translate. Use re.sub to remove the desired characters

Label Label


Using Cmp Argument

Rule ID: W1640

Description: Using the cmp argument for list.sort / sorted Using the cmp argument for list.sort or the sorted builtin should be avoided, since it was removed in Python 3. Using either key or functools.cmp_to_key should be preferred

Label Label

Bad Example
my_list = [3, 1, 2]
my_list.sort(cmp=lambda x, y: x - y) # cmp argument removed in Python 3
Good Example
from functools import cmp_to_key
my_list = [3, 1, 2]
my_list.sort(key=cmp_to_key(lambda x, y: x - y)) # Use cmp_to_key in Python 3

Cmp Method

Rule ID: W1630

Description: cmp method defined Used when a cmp method is defined (method is not used by Python 3)

Label Label

Bad Example
class MyClass:
def __cmp__(self, other): # __cmp__ is removed in Python 3
return cmp(self.value, other.value)
Good Example
class MyClass:
def __lt__(self, other): # Define rich comparison methods instead
return self.value < other.value

Coerce Method

Rule ID: W1614

Description: coerce method defined Used when a coerce method is defined (method is not used by Python 3)

Label Label

Bad Example
class MyClass:
def __coerce__(self, other):
return self.value, other.value # __coerce__ is not used in Python 3
Good Example
class MyClass:
def __add__(self, other):
return self.value + other.value # Use other rich comparison methods

Delslice Method

Rule ID: W1615

Description: delslice method defined Used when a delslice method is defined (method is not used by Python 3)

Label Label

Bad Example
class MyList(list):
def __delslice__(self, i, j): # __delslice__ is not used in Python 3
del self[i:j]
Good Example
class MyList(list):
def __delitem__(self, key): # Use __delitem__ instead
del self[key]

Div Method

Rule ID: W1642

Description: div method defined Used when a div method is defined. Using truediv and setting__div__ = truediv should be preferred.(method is not used by Python 3)

Label Label

Bad Example
class MyClass:
def __div__(self, other): # __div__ is removed in Python 3
return self.value / other.value
Good Example
class MyClass:
def __truediv__(self, other): # Use __truediv__ instead
return self.value / other.value

Getslice Method

Rule ID: W1616

Description: getslice method defined Used when a getslice method is defined (method is not used by Python 3)

Label Label

Bad Example
class MyList(list):
def __getslice__(self, i, j): # __getslice__ is not used in Python 3
return self[i:j]
Good Example
class MyList(list):
def __getitem__(self, key): # Use __getitem__ instead
return self[key]

Hex Method

Rule ID: W1628

Description: hex method defined Used when a hex method is defined (method is not used by Python 3)

Label Label

Bad Example
class MyClass:
def __hex__(self): # __hex__ is not used in Python 3
return hex(self.value)
Good Example
class MyClass:
def __repr__(self): # Use __repr__ or custom method instead
return f'{self.value:#x}'

Idiv Method

Rule ID: W1643

Description: idiv method defined Used when an idiv method is defined. Using itruediv and setting__idiv__ = itruediv should be preferred.(method is not used by Python 3)

Label Label

Bad Example
class MyClass:
def __idiv__(self, other): # __idiv__ is removed in Python 3
self.value /= other.value
Good Example
class MyClass:
def __itruediv__(self, other): # Use __itruediv__ instead
self.value /= other.value

Nonzero Method

Rule ID: W1629

Description: nonzero method defined Used when a nonzero method is defined (method is not used by Python 3)

Label Label

Bad Example
class MyClass:
def __nonzero__(self): # __nonzero__ is removed in Python 3
return bool(self.value)
Good Example
class MyClass:
def __bool__(self): # Use __bool__ instead
return bool(self.value)

Oct Method

Rule ID: W1627

Description: oct method defined Used when an oct method is defined (method is not used by Python 3)

Label Label

Bad Example
class MyClass:
def __oct__(self): # __oct__ is not used in Python 3
return oct(self.value)
Good Example
class MyClass:
def __repr__(self): # Use __repr__ or custom method instead
return f'{self.value:#o}'

Rdiv Method

Rule ID: W1644

Description: rdiv method defined Used when a rdiv method is defined. Using rtruediv and setting__rdiv__ = rtruediv should be preferred.(method is not used by Python 3)

Label Label

Bad Example
class MyClass:
def __rdiv__(self, other): # __rdiv__ is removed in Python 3
return other.value / self.value
Good Example
class MyClass:
def __rtruediv__(self, other): # Use __rtruediv__ instead
return other.value / self.value

Setslice Method

Rule ID: W1617

Description: setslice method defined Used when a setslice method is defined (method is not used by Python 3)

Label Label

Bad Example
class MyList(list):
def __setslice__(self, i, j, sequence): # __setslice__ is removed in Python 3
self[i:j] = sequence
Good Example
class MyList(list):
def __setitem__(self, key, value): # Use __setitem__ instead
self[key] = value

Apply Builtin

Rule ID: W1601

Description: apply built-in referenced Used when the apply built-in function is referenced (missing from Python 3)

Label Label

Bad Example
apply(func, (arg1, arg2)) # apply is removed in Python 3
Good Example
func(arg1, arg2) # Direct function call is valid in Python 3

Basestring Builtin

Rule ID: W1602

Description: basestring built-in referenced Used when the basestring built-in function is referenced (missing from Python 3)

Label Label

Bad Example
if isinstance(my_var, basestring): # basestring is removed in Python 3
print("It's a string")
Good Example
if isinstance(my_var, str): # Use str in Python 3
print("It's a string")

Buffer Builtin

Rule ID: W1603

Description: buffer built-in referenced Used when the buffer built-in function is referenced (missing from Python 3)

Label Label

Bad Example
my_buf = buffer(my_var) # buffer is removed in Python 3
Good Example
# buffer functionality is handled differently in Python 3, use memoryview or bytearray
my_buf = memoryview(my_var)

Cmp Builtin

Rule ID: W1604

Description: cmp built-in referenced Used when the cmp built-in function is referenced (missing from Python 3)

Label Label

Bad Example
result = cmp(a, b) # cmp is removed in Python 3
Good Example
result = (a > b) - (a < b) # Use comparison operators in Python 3

Coerce Builtin

Rule ID: W1605

Description: coerce built-in referenced Used when the coerce built-in function is referenced (missing from Python 3)

Label Label

Bad Example
result = coerce(a, b) # coerce is removed in Python 3

Dict Items Not Iterating

Rule ID: W1654

Description: dict.items referenced when not iterating Used when dict.items is referenced in a non-iterating context (returns an iterator in Python 3)

Label Label

Bad Example
my_items = my_dict.items() # This returns a view object in Python 3
Good Example
my_items = list(my_dict.items()) # Convert to list for Python 3 behavior

Dict Keys Not Iterating

Rule ID: W1655

Description: dict.keys referenced when not iterating Used when dict.keys is referenced in a non-iterating context (returns an iterator in Python 3)

Label Label

Bad Example
my_keys = my_dict.keys() # This returns a view object in Python 3
Good Example
my_keys = list(my_dict.keys()) # Convert to list for Python 3 behavior

Dict Values Not Iterating

Rule ID: W1656

Description: dict.values referenced when not iterating Used when dict.values is referenced in a non-iterating context (returns an iterator in Python 3)

Label Label

Bad Example
my_values = my_dict.values() # This returns a view object in Python 3
Good Example
my_values = list(my_dict.values()) # Convert to list for Python 3 behavior

Old Division

Rule ID: W1619

Description: division w/o future statement Used for non-floor division w/o a float literal or from future import division (Python 3 returns a float for int division unconditionally)

Label Label

Bad Example
result = 5 / 2 # Returns integer in Python 2 (invalid in Python 3)

Execfile Builtin

Rule ID: W1606

Description: execfile built-in referenced Used when the execfile built-in function is referenced (missing from Python 3)

Label Label

Bad Example
execfile('script.py') # execfile is removed in Python 3
Good Example
with open('script.py') as file:
exec(file.read()) # Use open and exec in Python 3

File Builtin

Rule ID: W1607

Description: file built-in referenced Used when the file built-in function is referenced (missing from Python 3)

Label Label

Bad Example
file_object = file('example.txt', 'r') # file is removed in Python 3
Good Example
file_object = open('example.txt', 'r') # Use open in Python 3

Filter Builtin Not Iterating

Rule ID: W1639

Description: filter built-in referenced when not iterating Used when the filter built-in is referenced in a non-iterating context (returns an iterator in Python 3)

Label Label

Bad Example
result = filter(lambda x: x > 0, my_list) # Returns iterator in Python 3, no list (invalid)
Good Example
result = list(filter(lambda x: x > 0, my_list)) # Convert to list for Python 3

No Absolute Import

Rule ID: W1618

Description: import missing from __future__ import absolute_import Used when an import is not accompanied by from future import absolute_import (default behaviour in Python 3)

Label Label

Bad Example
import mymodule # Without future import in Python 2
Good Example
from __future__ import absolute_import # Use absolute imports in Python 3
import mymodule

Input Builtin

Rule ID: W1632

Description: input built-in referenced Used when the input built-in is referenced (backwards-incompatible semantics in Python 3)

Label Label

Bad Example
user_input = input("Enter something: ") # Works differently in Python 2

Intern Builtin

Rule ID: W1634

Description: intern built-in referenced Used when the intern built-in is referenced (Moved to sys.intern in Python 3)

Label Label

Bad Example
my_interned = intern("example") # intern is moved in Python 3
Good Example
import sys
my_interned = sys.intern("example") # Use sys.intern() in Python 3

Long Builtin

Rule ID: W1608

Description: long built-in referenced Used when the long built-in function is referenced (missing from Python 3)

Label Label

Bad Example
my_num = long(123456789) # long is removed in Python 3
Good Example
my_num = int(123456789) # Use int in Python 3

Map Builtin Not Iterating

Rule ID: W1636

Description: map built-in referenced when not iterating Used when the map built-in is referenced in a non-iterating context (returns an iterator in Python 3)

Label Label

Bad Example
result = map(lambda x: x * 2, my_list) # Returns an iterator in Python 3
Good Example
result = list(map(lambda x: x * 2, my_list)) # Convert to list in Python 3

Next Method Defined

Rule ID: W1653

Description: next method defined Used when a next method is defined that would be an iterator in Python 2 but is treated as a normal function in Python 3

Label Label

Bad Example
class MyClass:
def next(self): # Treated differently in Python 3
return 42
Good Example
class MyClass:
def __next__(self): # Use __next__ in Python 3
return 42

Invalid Str Codec

Rule ID: W1646

Description: non-text encoding used in str.decode Used when using str.encode or str.decode with a non-text encoding. Use codecs module to handle arbitrary codecs

Label Label

Bad Example
encoded_str = "hello".encode("hex") # Non-text codec is removed in Python 3
Good Example
import codecs
encoded_str = codecs.encode("hello", "hex") # Use codecs module in Python 3

Range Builtin Not Iterating

Rule ID: W1638

Description: range built-in referenced when not iterating Used when the range built-in is referenced in a non-iterating context (returns a range in Python 3)

Label Label

Bad Example
result = range(10) # Returns an iterator in Python 3
Good Example
result = list(range(10)) # Convert to list in Python 3

Raw_input Builtin

Rule ID: W1609

Description: raw_input built-in referenced Used when the raw_input built-in function is referenced (missing from Python 3)

Label Label

Bad Example
user_input = raw_input("Enter something: ") # raw_input is removed in Python 3
Good Example
user_input = input("Enter something: ") # Use input in Python 3

Reduce Builtin

Rule ID: W1610

Description: reduce built-in referenced Used when the reduce built-in function is referenced (missing from Python 3)

Label Label

Bad Example
result = reduce(lambda x, y: x + y, my_list) # reduce is removed from built-ins in Python 3
Good Example
from functools import reduce # Import from functools in Python 3
result = reduce(lambda x, y: x + y, my_list)

Reload Builtin

Rule ID: W1626

Description: reload built-in referenced Used when the reload built-in function is referenced (missing from Python 3). You can use instead imp.reload or importlib.reload

Label Label

Bad Example
reload(mymodule) # reload is removed in Python 3
Good Example
from importlib import reload # Use importlib.reload in Python 3
reload(mymodule)

Round Builtin

Rule ID: W1633

Description: round built-in referenced Used when the round built-in is referenced (backwards-incompatible semantics in Python 3)

Label Label

Bad Example
rounded = round(5.675, 2) # Different behavior in Python 3 for rounding

Sys Max Int

Rule ID: W1647

Description: sys.maxint removed in Python 3 Used when accessing sys.maxint. Use sys.maxsize instead

Label Label

Bad Example
import sys
print(sys.maxint) # maxint is removed in Python 3
Good Example
import sys
print(sys.maxsize) # Use sys.maxsize in Python 3

Unichr Builtin

Rule ID: W1635

Description: unichr built-in referenced Used when the unichr built-in is referenced (Use chr in Python 3)

Label Label

Bad Example
char = unichr(97) # unichr is removed in Python 3
Good Example
char = chr(97) # Use chr in Python 3

Unicode Builtin

Rule ID: W1612

Description: unicode built-in referenced Used when the unicode built-in function is referenced (missing from Python 3)

Label Label

Bad Example
my_str = unicode("example") # unicode is removed in Python 3
Good Example
my_str = str("example") # Use str in Python 3

Xrange Builtin

Rule ID: W1613

Description: xrange built-in referenced Used when the xrange built-in function is referenced (missing from Python 3)

Label Label

Bad Example
for i in xrange(10): # xrange is removed in Python 3
print(i)
Good Example
for i in range(10): # Use range in Python 3
print(i)

Zip Builtin Not Iterating

Rule ID: W1637

Description: zip built-in referenced when not iterating Used when the zip built-in is referenced in a non-iterating context (returns an iterator in Python 3)

Label Label

Bad Example
result = zip(list1, list2) # Returns an iterator in Python 3
Good Example
result = list(zip(list1, list2)) # Convert to list in Python 3

Simplifiable Condition

Rule ID: R1726

Description: A boolean condition is able to be simplified

Label Label

Bad Example
def has_bananas(bananas) -> bool:
return bool(bananas or False) # [simplifiable-condition]
Good Example
def has_bananas(bananas) -> bool:
return bool(bananas)

Condition Evals To Constant

Rule ID: R1727

Description: A boolean condition can be simplified to a constant value

Label Label

Bad Example
def is_a_vegetable(vegetable):
return bool(vegetable in {"carrot", "broccoli"} or True) # [condition-evals-to-constant]
Good Example
def is_a_vegetable(vegetable):
return vegetable in {"carrot", "broccoli"}

Simplify Boolean Expression

Rule ID: R1709

Description: Emitted when redundant pre-python 2.5 ternary syntax is used

Label Label

Bad Example
def has_grapes(grapes, oranges=None) -> bool:
return oranges and False or grapes # [simplify-boolean-expression]
Good Example
def has_grapes(grapes, oranges=None) -> bool:
return grapes

Consider Using In

Rule ID: R1714

Description: To check if a variable is equal to one of many values, combine the values into a tuple and check if the variable is contained in it instead of checking for equality against each of the values. This is faster and less verbose

Label Label

Bad Example
def fruit_is_yellow(fruit):
# +1: [consider-using-in]
return fruit == "banana" or fruit == "lemon" or fruit == "pineapple"
Good Example
def fruit_is_yellow(fruit):
return fruit in {"banana", "lemon", "pineapple"}

Consider Merging Isinstance

Rule ID: R1701

Description: Multiple consecutive isinstance calls can be merged into one

Label Label

Bad Example
from typing import Any

def is_string(value: Any) -> bool:
# +1: [consider-merging-isinstance]
return isinstance(value, str) or isinstance(value, bytes)
Good Example
from typing import Any

def is_string(value: Any) -> bool:
return isinstance(value, (str, bytes))

Super With Arguments

Rule ID: R1725

Description: Consider using Python 3 style super() without arguments. Emitted when calling the super() builtin with the current class and instance. On Python 3 these arguments are the default and they can be omitted

Label Label

Bad Example
class Fruit:
pass

class Banana(Fruit):
def __init__(self):
super(Banana, self).__init__() # [super-with-arguments]
Good Example
class Fruit:
pass

class Banana(Fruit):
def __init__(self):
super().__init__()

Consider Using Dict Comprehension

Rule ID: R1717

Description: Emitted when detect the creation of a dictionary using the dict() callable and a transient list. Although there is nothing syntactically wrong with this code, it is hard to read and can be simplified to a dict comprehension. Also it is faster since you don't need to create another transient list

Label Label

Bad Example
fruits = ["apple", "pear", "banana"]

# +1: [consider-using-dict-comprehension]
FRUIT_LENGTHS = dict([(fruit, len(fruit)) for fruit in fruits])
Good Example
fruits = ["apple", "pear", "banana"]

FRUIT_LENGTHS = {fruit: len(fruit) for fruit in fruits}

Consider Using Set Comprehension

Rule ID: R1718

Description: Although there is nothing syntactically wrong with this code, it is hard to read and can be simplified to a set comprehension. Also, it is faster since you don't need to create another transient list

Label Label

Bad Example
fruits = ["apple", "banana", "banana", "pear", "kiwi", "kiwi"]

# +1: [consider-using-set-comprehension]
UNIQUE_FRUITS = set([fruit for fruit in fruits if fruit.startswith('k')])
Good Example
fruits = ["apple", "banana", "banana", "pear", "kiwi", "kiwi"]

UNIQUE_FRUITS = {fruit for fruit in fruits if fruit.startswith('k')}

Consider Using Get

Rule ID: R1715

Description: Using the builtin dict.get for key lookups is preferred to avoid KeyError exceptions

Label Label

Bad Example
knights = {"Arthur": "the brave", "Lancelot": "the noble"}

if "Arthur" in knights: # [consider-using-get]
DESCRIPTION = knights["Arthur"]
else:
DESCRIPTION = ""
Good Example
knights = {"Arthur": "the brave", "Lancelot": "the noble"}

description = knights.get("Arthur", "")

Consider Using Join

Rule ID: R1713

Description: Using str.join(sequence) is faster, uses less memory and increases readability compared to for-loop iteration

Label Label

Bad Example
def numbers_to_string(numbers):
formatted_number = ''
for number in numbers:
formatted_number += str(number) # [consider-using-join]
return formatted_number

print(numbers_to_string([1, 2, 3]))
Good Example
print(''.join(map(str, [1, 2, 3])))

Consider Using Sys Exit

Rule ID: R1722

Description: Instead of using exit() or quit(), consider using the sys.exit()

Label Label

Bad Example
if __name__ == '__main__':
age = input('Enter your age: ')
print(f'Your age is {age}')
exit(0) # [consider-using-sys-exit]
Good Example
import sys

if __name__ == '__main__':
age = input('Enter your age: ')
print(f'Your age is {age}')
sys.exit(0)

Consider Using Ternary

Rule ID: R1706

Description: One of known pre-python 2.5 ternary syntax is used

Label Label

Bad Example
a, b = 5, 10
result = a > b and a or b # [consider-using-ternary]
Good Example
a, b = 5, 10
result = a if a > b else b

Consider Swap Variables

Rule ID: R1712

Description: You do not have to use a temporary variable in order to swap variables. Using tuple unpacking to directly swap variables makes the intention more clear

Label Label

Bad Example
x = 3
y = 5

temp = x # [consider-swap-variables]
x = y
y = temp
Good Example
x = 3
y = 5

x, y = y, x

Trailing Comma Tuple

Rule ID: R1707

Description: In Python, a tuple is created by the comma symbol, not by parentheses. Using a trailing comma can create unwanted tuples, so always use parentheses for clarity.

Label Label

Bad Example
DIRECTIONS = 'left', 'right', 'up', 'down', # [trailing-comma-tuple]
Good Example
DIRECTIONS = ('left', 'right', 'up', 'down')

Stop Iteration Return

Rule ID: R1708

Description: According to PEP479, raising StopIteration in a generator can lead to bugs. It's better to rely on the natural termination of a generator.

Label Label

Bad Example
def color_generator():
for color in ['red', 'blue']:
yield color
raise StopIteration # [stop-iteration-return]
Good Example
def color_generator():
"""No need for an explicit return in this simple case."""
for color in ['red', 'blue']:
yield color

Inconsistent Return Statements

Rule ID: R1710

Description: All return statements in a function should be consistent. If some return a value, others should explicitly return None.

Label Label

Bad Example
def find_maximum(value: int) -> int | None: # [inconsistent-return-statements]
if value > 0:
return value
Good Example
def find_maximum(value: int) -> int | None:
if value > 0:
return value
return None

Redefined Argument From Local

Rule ID: R1704

Description: A local name is redefining an argument, which might suggest a potential error. This is relevant for iterations and similar constructs.

Label Label

Bad Example
def calculate(radius=5.5):
# +1: [redefined-argument-from-local]
for radius, area in [(3, 28.27), (5, 78.54)]:
print(radius, area)
Good Example
def calculate(radius=5.5):
for r, area in [(3, 28.27), (5, 78.54)]:
print(radius, r, area)

Consider Using In

Rule ID: R1716

Description: When testing for membership in a collection inside a loop, it is preferable to structure your loop to avoid deeply nested blocks. Using continue statements can lead to complex control flows, which is harder to read and maintain.

Label Label

Bad Example
for fruit in fruits:
if fruit in UNIQUE_FRUITS: # [consider-using-in]
print(fruit)
continue
print(fruit)
Good Example
for fruit in fruits:
if fruit in UNIQUE_FRUITS:
print(fruit)
continue
else:
print(fruit)

Simplifiable If Expression

Rule ID: R1719

Description: An if expression can be replaced with bool(test)

Label Label

Bad Example
VEHICLES = ["car", "boat", "rocket", "this example"]

def is_vehicle(an_object):
return True if an_object in VEHICLES else False # [simplifiable-if-expression]


def is_not_vehicle(an_object):
return False if an_object in VEHICLES else True # [simplifiable-if-expression]
Good Example
VEHICLES = ["car", "boat", "rocket", "this example"]

def is_vehicle(an_object):
return an_object in VEHICLES

def is_not_vehicle(an_object):
return an_object not in VEHICLES

Simplifiable If Statement

Rule ID: R1703

Description: An if statement can be replaced with bool(test)

Label Label

Bad Example
WILD_ANIMALS = ["lion", "tiger", "elephant", "this example"]

def is_wild_animal(an_object):
# +1: [simplifiable-if-statement]
if isinstance(an_object, Animal) and an_object in WILD_ANIMALS:
is_wild = True
else:
is_wild = False
return is_wild
Good Example
WILD_ANIMALS = ["lion", "tiger", "elephant", "this example"]

def is_wild_animal(an_object):
is_wild = isinstance(an_object, Animal) and an_object.name in WILD_ANIMALS
return is_wild

Too Many Nested Blocks

Rule ID: R1702

Description: A function or a method has too many nested blocks. This makes the code less understandable and maintainable. Maximum number of nested blocks for function / method body is 5 by default

Label Label

Bad Example
def validate_colors(colors):
if len(colors) > 2: # [too-many-nested-blocks]
if "red" in colors:
if "blue" in colors:
count = colors["blue"]
if count % 2:
if "green" in colors:
if count == 2:
return True
return False
Good Example
def validate_colors(colors):
if len(colors) > 2 and "red" in colors and "blue" in colors:
count = colors["blue"]
if count % 2 and "green" in colors and count == 2:
return True
return False

No Else Break

Rule ID: R1723

Description: Used in order to highlight an unnecessary block of code following an if containing a break statement. As such, it will warn when it encounters an else following a chain of ifs, all of them containing a break statement

Label Label

Bad Example
def next_ten_numbers(iterator):
for i, item in enumerate(iterator):
if i == 10: # [no-else-break]
break
else:
yield item
Good Example
def next_ten_numbers(iterator):
for i, item in enumerate(iterator):
if i == 10:
break
yield item

No Else Continue

Rule ID: R1724

Description: Used in order to highlight an unnecessary block of code following an if containing a continue statement. As such, it will warn when it encounters an else following a chain of ifs, all of them containing a continue statement

Label Label

Bad Example
def odd_number_under(n: int):
for i in range(n):
if i % 2 == 0: # [no-else-continue]
continue
else:
yield i
Good Example
def odd_number_under(n: int):
for i in range(n):
if i % 2 == 0:
continue
yield i

No Else Raise

Rule ID: R1720

Description: Used in order to highlight an unnecessary block of code following an if containing a raise statement. As such, it will warn when it encounters an else following a chain of ifs, all of them containing a raise statement

Label Label

Bad Example
def float_sum(a: float, b: float) -> float:
if not (isinstance(a, float) and isinstance(b, float)): # [no-else-raise]
raise ValueError("Function supports only float parameters.")
else:
return a + b
Good Example
def float_sum(a: float, b: float) -> float:
if not (isinstance(a, float) and isinstance(b, float)):
raise ValueError("Function supports only float parameters.")
return a + b

No Else Return

Rule ID: R1705

Description: Unnecessary else after return. Used in order to highlight an unnecessary block of code following an if containing a return statement. As such, it will warn when it encounters an else following a chain of ifs, all of them containing a return statement

Label Label

Bad Example
def compare_strings(a: str, b: str) -> int:
if a == b: # [no-else-return]
return 0
elif a < b:
return -1
else:
return 1
Good Example
def compare_strings(a: str, b: str) -> int:
if a == b:
return 0
if a < b:
return -1
return 1

Unnecessary Comprehension

Rule ID: R1721

Description: Instead of using an identity comprehension, consider using the list, dict or set constructor. It is faster and simpler

Label Label

Bad Example
ANIMALS = ["cat", "dog", "fish", "this example"]

UNIQUE_ANIMALS = {animal for animal in ANIMALS} # [unnecessary-comprehension]
Good Example
ANIMALS = ["cat", "dog", "fish", "this example"]

UNIQUE_ANIMALS = set(ANIMALS)

Useless Return

Rule ID: R1711

Description: A function is returning a value that is unnecessary. This could be useful to identify functions that should simply be called for their side effects

Label Label

Bad Example
import os

def show_current_directory():
return os.getcwd() # [useless-return]
Good Example
import os

def show_current_directory():
print(os.getcwd())

Unneeded Not

Rule ID: C0113

Description: A boolean expression contains an unnecessary negation. Removing it increases readability and avoids potential confusion.

Label Label

Bad Example
if not (x == y): # [unneeded-not]
Good Example
if x != y:

Consider Iterating Dictionary

Rule ID: C0201

Description: When iterating over a dictionary, there's no need to explicitly use .keys(). Just iterate through the dictionary itself for simplicity.

Label Label

Bad Example
CARS = {'Toyota': 3, 'Honda': 5, 'Ford': 2}

for car in CARS.keys(): # [consider-iterating-dictionary]
print(car)
Good Example
CARS = {'Toyota': 3, 'Honda': 5, 'Ford': 2}

for car in CARS:
print(car)

Fuzzy Comparison

Rule ID: C0200

Description: Fuzzy comparisons can produce unexpected results. Use a mathematical equivalence instead.

Label Label

Bad Example
def is_square(n):
return n == n ** 0.5 # [fuzzy-comparison]

def is_cube(n):
return n == n ** (1/3) # [fuzzy-comparison]
Good Example
def is_square(n):
return n ** 2 == n

def is_cube(n):
return n ** (1/3) == n

Len As Condition

Rule ID: C1801

Description: Pylint detects that len(sequence) is being used without explicit comparison inside a condition to determine if a sequence is empty. Instead of coercing the length to a boolean, either rely on the fact that empty sequences are false or compare the length against a scalar.

Label Label

Bad Example
if len(sequence) == 0: # [unnecessary-length-check]
Good Example
if not sequence: # More Pythonic way to check for an empty sequence

Invalid Envvar Value

Rule ID: E1507

Description: Env manipulation functions support only string type arguments.

Label Label

Bad Example
import os
os.getenv(True) # [invalid-envvar-value]
Good Example
import os

os.getenv("TRUE")

Bad Open Mode

Rule ID: W1501

Description: Python supports r, w, a[, x] modes with b, +, and U (only with r) options.

Label Label

Bad Example
def open_and_get_content(file_path):
with open(file_path, "abc") as file: # [bad-open-mode]
return file.read()
Good Example
def open_and_get_content(file_path):
with open(file_path, "r") as file:
return file.read()

Invalid Envvar Default

Rule ID: W1508

Description: Env manipulation functions return None or str values. Supplying anything different as a default may cause bugs. See https://docs.python.org/3/library/os.html#os.getenv for more details.

Label Label

Bad Example
import os
env = os.getenv("API_URL", []) # [invalid-envvar-default]
Good Example
import os
env = os.getenv("API_URL", "default_value")

Redundant Unittest Assert

Rule ID: W1503

Description: The first argument of assertTrue and assertFalse is a condition. If a constant is passed as a parameter, that condition will always be true. In this case, a warning should be emitted.

Label Label

Bad Example
import unittest

class DummyTestCase(unittest.TestCase):
def test_dummy(self):
self.assertTrue(1) # [redundant-unittest-assert]
Good Example
import unittest

class DummyTestCase(unittest.TestCase):
def test_dummy(self):
actual = "result"
self.assertEqual(actual, "expected")

Shallow Copy Environ

Rule ID: W1507

Description: os.environ is not a dict object but a proxy object, so a deep copy may still affect the original object. See https://bugs.python.org/issue15373 for reference.

Label Label

Bad Example
import copy
import os

copied_env = copy.deepcopy(os.environ) # [deep-copy-environ]
Good Example
import os

copied_env = os.environ.copy()

Boolean Datetime

Rule ID: W1502

Description: Using datetime.date in a boolean context can hide subtle bugs when the date they represent is a specific value like the epoch. This behavior was fixed in Python 3.5. See http://bugs.python.org/issue13936 for reference. It can't be emitted when using Python >= 3.5.

Label Label

Bad Example
import datetime

if not datetime.date(2000, 1, 1): # [boolean-datetime]
print("Date is valid.")
Good Example
import datetime

today = datetime.date.today()
if today >= datetime.date(2000, 1, 1):
print("Date is valid.")

Deprecated Method

Rule ID: W1505

Description: The method is marked as deprecated and will be removed in a future version of Python. Consider looking for an alternative in the documentation.

Label Label

Bad Example
old_function() # [deprecated-function]
Good Example
new_function()

Subprocess Popen Preexec Fn

Rule ID: W1509

Description: The preexec_fn parameter is not safe to use in the presence of threads in your application. The child process could deadlock before exec is called. If you must use it, keep it trivial! Minimize the number of libraries you call into.

Label Label

Bad Example
import subprocess

def do_nothing():
pass

subprocess.Popen(preexec_fn=do_nothing) # [subprocess-popen-preexec-fn]
Good Example
import subprocess

subprocess.Popen()

Subprocess Run Check

Rule ID: W1510

Description: The check parameter should always be used with explicitly set check keyword to make clear what the error-handling behavior is.

Label Label

Bad Example
import subprocess
proc = subprocess.run(["echo", "Hello World"]) # [subprocess-run-check]
Good Example
import subprocess
proc = subprocess.run(["echo", "Hello World"], check=False)

Bad Thread Instantiation

Rule ID: W1506

Description: The warning is emitted when a threading.Thread class is instantiated without the target function being passed. By default, the first parameter is the group param, not the target param.

Label Label

Bad Example
import threading

def thread_function():
print("Thread running")

thread = threading.Thread(target=thread_function, args=None) # [bad-thread-instantiation]
thread.start()
Good Example
import threading

def thread_function(n):
print(n)

thread = threading.Thread(target=thread_function, args=(5,))
thread.start()

Bad String Format Type

Rule ID: E1307

Description: A type required by the format string is not suitable for the actual argument type.

Label Label

Bad Example
print("%s" % 10) # [bad-string-format-type]
Good Example
print("%s" % "10")

Format Needs Mapping

Rule ID: E1303

Description: A format string that uses named conversion specifiers is used with an argument that is not a mapping

Label Label

Bad Example
print("%(a)s %(b)s" % ["foo", "bar"]) # [format-needs-mapping]
Good Example
print("%(a)s %(b)s" % {"a": "foo", "b": "bar"})

Truncated Format String

Rule ID: E1301

Description: A format string terminates before the end of a conversion specifier

Label Label

Bad Example
NUM_1 = 5

print("value %2" % NUM_1) # [truncated-format-string]
Good Example
NUM_1 = 5

print(f"value {NUM_1}")

Missing Format String Key

Rule ID: E1304

Description: A format string that uses named conversion specifiers is used with a dictionary that doesn't contain all the keys required by the format string

Label Label

Bad Example
# +1: [missing-format-string-key]
vegetable_prices = """
Carrot: %(carrot_price)d ¤
Potato: %(potato_price)d ¤
""" % {
"carrot_price": 30
}
Good Example
vegetable_prices = """
Carrot: %(carrot_price)d ¤
Potato: %(potato_price)d ¤
""" % {
"carrot_price": 30,
"potato_price": 45,
}

Mixed Format String

Rule ID: E1302

Description: A format string contains both named and unnamed conversion specifiers. This is also used when a named conversion specifier contains * for the minimum field width and/or precision

Label Label

Bad Example
print("a=%(a)d, b=%d" % (2, 3)) # [mixed-format-string]
Good Example
print("a=%(a)d, b=%(b)d" % {"a": 2, "b": 3})

Too Few Format Args

Rule ID: E1306

Description: A format string that uses unnamed conversion specifiers is given too few arguments

Label Label

Bad Example
print("The weather is {0}, and tomorrow will be {1}".format("sunny")) # [too-few-format-args]
Good Example
print("The weather is {0}, and tomorrow will be {1}".format("sunny", "cloudy"))

Bad Str Strip Call

Rule ID: E1310

Description: The argument to a str.{l,r,}strip call contains a duplicate character

Label Label

Bad Example
"Python Programming".strip("Pyt") # [bad-str-strip-call]
# >>> 'hon Programming'
Good Example
"Python Programming".strip("Pytho")
# >>> 'n Programming'

Too Many Format Args

Rule ID: E1305

Description: A format string that uses unnamed conversion specifiers is given too many arguments

Label Label

Bad Example
# +1: [too-many-format-args]
print("This year is {0}, next year will be {1}".format("2023", "2024", "2025"))
Good Example
print("This year is {0}, next year will be {1}".format("2023", "2024"))

Bad Format Character

Rule ID: E1300

Description: An unsupported format character is used in a format string

Label Label

Bad Example
print("%d %q" % (10, 20)) # [bad-format-character]
Good Example
print("%d %d" % (10, 20))

Anomalous Unicode Escape In String

Rule ID: W1402

Description: An escape like \u is encountered in a byte string where it has no effect

Label Label

Bad Example
print(b"%𐍈" % b"data") # [anomalous-unicode-escape-in-string]
Good Example
print(b"\x50\u2341" % b"data")

Anomalous Backslash In String

Rule ID: W1401

Description: A backslash is in a literal string but not as an escape

Label Label

Bad Example
path = "c:\folder" # [syntax-error]
Good Example
path = "c:\\folder"

Duplicate String Formatting Argument

Rule ID: W1308

Description: We detect that a string formatting is repeating an argument instead of using named string arguments

Label Label

Bad Example
# pylint: disable=missing-docstring, consider-using-f-string

SKY = "sky ☁️"
STAR = "star ✨"

# +1: [duplicate-string-formatting-argument,duplicate-string-formatting-argument]
CONST = """
Twinkle twinkle little {}, {}
How I wonder what you {}, {}
Up above the world so {}, {}
Like a diamond in the {}, {}!
""".format(
STAR,
STAR,
SKY,
SKY,
SKY,
STAR,
STAR
)
Good Example
# pylint: disable=missing-docstring, consider-using-f-string

SKY = "sky ☁️"
STAR = "star ✨"

CONST = """
Twinkle twinkle little {star}, {star}
How I wonder what you {sky}, {sky}
Up above the world so {sky}, {sky}
Like a diamond in the {star}, {star}!
""".format(
star=STAR, sky=SKY
)

Format Combined Specification

Rule ID: W1305

Description: A PEP 3101 format string contains both automatic field numbering (e.g. {}) and manual field specification (e.g. {0})

Label Label

Bad Example
print("{} {2}".format("apple", "banana")) # [format-combined-specification]
Good Example
print("{0} {1}".format("apple", "banana"))

Bad Format String Key

Rule ID: W1300

Description: A format string that uses named conversion specifiers is used with a dictionary whose keys are not all strings

Label Label

Bad Example
print("%(key1)s" % {"key1": "value", 100: "num"}) # [bad-format-string-key]
Good Example
print("%(key1)s, %(key2)s" % {"key1": "value", "key2": "num"})

Implicit Str Concat

Rule ID: W1404

Description: Implicit string concatenation found. String literals are implicitly concatenated in a literal iterable definition: maybe a comma is missing?

Label Label

Bad Example
with open("file.txt" "w") as f: # [implicit-str-concat]
f.write("data")
Good Example
with open("file.txt", "w") as f:
f.write("data")

Bad Format String

Rule ID: W1302

Description: A PEP 3101 format string is invalid

Label Label

Bad Example
print("{b[0] * b[1]}".format(b=[2, 3])) # [bad-format-string]
Good Example
print("{b[0]} * {b[1]}".format(b=[2, 3]))

Missing Format Attribute

Rule ID: W1306

Description: A PEP 3101 format string uses an attribute specifier (e.g., {0.real}), but the argument passed for formatting doesn't have that attribute

Label Label

Bad Example
print("{0.imag}".format(5)) # [missing-format-attribute]
Good Example
print("{0.imag}".format(5j))

Missing Format Argument Key

Rule ID: W1303

Description: A PEP 3101 format string that uses named fields doesn't receive one or more required keywords

Label Label

Bad Example
print("My pet is a {type} named {name}".format(type="dog")) # [missing-format-argument-key]
Good Example
print("My pet is a {type} named {name}".format(type="dog", name="Buddy"))

Inconsistent Quotes

Rule ID: W1405

Description: Quote delimiter is inconsistent with the rest of the file. Quote delimiters are not used consistently throughout a module (with allowances made for avoiding unnecessary escaping)

Label Label

Bad Example
import time

print('Current time: ', time.strftime("%H:%M:%S")) # [inconsistent-quotes]
Good Example
import time

print("Current time: ", time.strftime("%H:%M:%S"))

Unused Format String Argument

Rule ID: W1304

Description: A PEP 3101 format string that uses named fields is used with an argument that is not required by the format string

Label Label

Bad Example
print("{a} {b}".format(a=4, b=5, c=6)) # [unused-format-string-argument]
Good Example
print("{a} {b} {c}".format(a=4, b=5, c=6))

Unused Format String Key

Rule ID: W1301

Description: A format string that uses named conversion specifiers is used with a dictionary that contains keys not required by the format string

Label Label

Bad Example
"The lazy %(animal)s sleeps all day." % {
"animal": "cat",
"activity": "jumps",
}
# -4: [unused-format-string-key]
Good Example
"The lazy %(animal)s %(activity)s all day." % {
"animal": "cat",
"activity": "jumps",
}

F String Without Interpolation

Rule ID: W1309

Description: Using an f-string that does not have any interpolated variables. This occurs when an f-string is used, but it can be a normal string or a potential bug in the code

Label Label

Bad Example
x = 3
y = 4
print(f"x multiplied by y equals x * y") # [f-string-without-interpolation]
Good Example
x = 3
y = 4
print(f"{x} multiplied by {y} equals {x * y}")

Invalid Format Index

Rule ID: W1307

Description: A PEP 3101 format string uses a lookup specifier ({a[2]}), but the argument passed for formatting doesn't contain or doesn't have that key as an attribute

Label Label

Bad Example
fruits = ["mango"]
print('The third fruit is {fruits[2]}'.format(fruits=fruits)) # [invalid-format-index]
Good Example
fruits = ["mango", "apple", "banana"]
print("The third fruit is {fruits[2]}".format(fruits=fruits))

Unsupported Assignment Operation

Rule ID: E1137

Description: Emitted when an object does not support item assignment (i.e., doesn't define the __setitem__ method)

Label Label

Bad Example
def get_colors(colors):
for color in colors:
print(color)

get_colors(["blue"])[0] = "red" # [unsupported-assignment-operation]
Good Example
def get_colors(colors):
for color in colors:
print(color)

return []

get_colors(["blue"])[0] = "red"

Unsupported Delete Operation

Rule ID: E1138

Description: Emitted when an object does not support item deletion (i.e. doesn't define __delitem__ method)

Label Label

Bad Example
VEGETABLES = ("carrot", "tomato", "pepper")

del VEGETABLES[1] # [unsupported-delete-operation]
Good Example
VEGETABLES = ["carrot", "tomato", "pepper"]

del VEGETABLES[1]

Invalid Unary Operand Type

Rule ID: E1130

Description: Emitted when a unary operand is used on an object which does not support this type of operation

Label Label

Bad Example
cookies = 5
missing_cookies = str
cookies = -missing_cookies # [invalid-unary-operand-type]
Good Example
cookies = 5
missing_cookies = 2
cookies -= missing_cookies

Unsupported Binary Operation

Rule ID: E1131

Description: Emitted when a binary arithmetic operation between two operands is not supported

Label Label

Bad Example
color = "blue" & None # [unsupported-binary-operation]
shape = {} | None # [unsupported-binary-operation]
Good Example
masked = 0b110101 & 0b101001
result = 0xABCD | 0x1234

No Member

Rule ID: E1101

Description: A variable is accessed for a non-existent member

Label Label

Bad Example
from os import path

location = path(".").drives # [no-member]

class Dog:
def bark(self):
print("Bark")

Dog().run() # [no-member]
Good Example
from os import path

location = path.abspath(".")

class Dog:
def bark(self):
print("Bark")

Dog().bark()

Not Callable

Rule ID: E1102

Description: An object being called has been inferred to a non callable object

Label Label

Bad Example
AGE = 25
print(AGE()) # [not-callable]
Good Example
AGE = 25
print(AGE)

Redundant Keyword Arg

Rule ID: E1124

Description: A function call would result in assigning multiple values to a function parameter, one value from a positional argument and one from a keyword argument

Label Label

Bad Example
def cube(x):
return x * x * x

cube(3, x=2) # [redundant-keyword-arg]
Good Example
def cube(x):
return x * x * x

cube(3)

Assignment From No Return

Rule ID: E1111

Description: An assignment is done on a function call but the inferred function doesn't return anything

Label Label

Bad Example
def subtract(x, y):
print(x - y)

result = subtract(7, 3) # [assignment-from-no-return]
Good Example
def subtract(x, y):
return x - y

result = subtract(7, 3)

Assignment From None

Rule ID: E1128

Description: An assignment is done on a function call but the inferred function returns nothing but None

Label Label

Bad Example
def compute():
return None

result = compute() # [assignment-from-none]
Good Example
def compute():
return None

result = compute() if compute() else 42

Not Context Manager

Rule ID: E1129

Description: An instance in a with statement doesn't implement the context manager protocol (__enter__/__exit__)

Label Label

Bad Example
class MyFileHandler:
def __enter__(self):
print('Opening file')

with MyFileHandler() as f: # [not-context-manager]
print('Processing file')
Good Example
class MyFileHandler:
def __enter__(self):
print('Opening file')

def __exit__(self, *exc):
print('Closing file')

with MyFileHandler() as f:
print('Processing file')

Unhashable Dict Key

Rule ID: E1140

Description: Emitted when a dict key is not hashable (i.e. doesn't define hash method)

Label Label

Bad Example
d = {[1, 2, 3]: 'numbers'} # [unhashable-dict-key]
Good Example
d = {(1, 2, 3): 'tuple-key'}

Repeated Keyword

Rule ID: E1132

Description: Emitted when a function call got multiple values for a keyword

Label Label

Bad Example
def greet(name, msg='Hello'):
return f'{msg}, {name}'

greet('John', msg='Hi', **{'msg': 'Welcome'}) # [repeated-keyword]
Good Example
def greet(name, msg='Hello'):
return f'{msg}, {name}'

greet('John', msg='Hi')

Invalid Metaclass

Rule ID: E1139

Description: Emitted whenever we can detect that a class is using, as a metaclass, something which might be invalid for using as a metaclass

Label Label

Bad Example
class Car(metaclass=str): # [invalid-metaclass]
pass
Good Example
class Vehicle:
pass

class Car(Vehicle):
pass

Missing Kwoa

Rule ID: E1125

Description: A function call does not pass a mandatory keyword-only argument

Label Label

Bad Example
def divide(dividend, *, divisor):
return dividend / divisor

def calculate(*args, **kwargs):
divide(*args) # [missing-kwoa]
Good Example
def divide(dividend, *, divisor):
return dividend / divisor

def calculate(*args, **kwargs):
divide(*args, **kwargs)

No Value For Parameter

Rule ID: E1120

Description: A function call passes too few arguments

Label Label

Bad Example
def multiply(x, y):
return x * y

multiply(4) # [no-value-for-parameter]
Good Example
def multiply(x, y):
return x * y

multiply(4, 5)

Not An Iterable

Rule ID: E1133

Description: A non-iterable value is used in place where an iterable is expected

Label Label

Bad Example
for char in 100: # [not-an-iterable]
pass
Good Example
for char in '100':
pass

Not A Mapping

Rule ID: E1134

Description: A non-mapping value is used in place where mapping is expected

Label Label

Bad Example
def print_animals(**animals):
print(animals)

print_animals(**list('cat', 'dog')) # [not-a-mapping]
Good Example
def print_animals(**animals):
print(animals)

print_animals(**dict(cat=1, dog=2))

Invalid Sequence Index

Rule ID: E1126

Description: A sequence type is indexed with an invalid type. Valid types are ints, slices, and objects with an __index__ method

Label Label

Bad Example
colors = ['red', 'green', 'blue']
print(colors['green']) # [invalid-sequence-index]
Good Example
colors = ['red', 'green', 'blue']
print(colors[1])

Invalid Slice Index

Rule ID: E1127

Description: A slice index is not an integer, None, or an object with an __index__ method

Label Label

Bad Example
NUMBERS = [1, 2, 3, 4]

FIRST_TWO = NUMBERS[:"2"] # [invalid-slice-index]
Good Example
NUMBERS = [1, 2, 3, 4]

FIRST_TWO = NUMBERS[:2]

Too Many Function Args

Rule ID: E1121

Description: A function call passes too many positional arguments. Maximum number of arguments for function/method is 5 by default

Label Label

Bad Example
class Vehicle:
def __init__(self, type):
self.type = type

car = Vehicle("sedan", "car", "2024") # [too-many-function-args]
Good Example
class Vehicle:
def __init__(self, type, model):
self.type = type
self.model = model

car = Vehicle("sedan", "2024")

Unexpected Keyword Arg

Rule ID: E1123

Description: A function call passes a keyword argument that doesn't correspond to one of the function's parameter names

Label Label

Bad Example
def greet(name="John", age=25):
print(f"Name: {name}, Age: {age}")

greet(name="Alice", age=30, gender="female") # [unexpected-keyword-arg]
Good Example
def greet(name="John", age=25):
print(f"Name: {name}, Age: {age}")

greet(name="Alice", age=30)

Dict Iter Missing Items

Rule ID: E1141

Description: Emitted when trying to iterate through a dict without calling .items()

Label Label

Bad Example
capitals = {"France": "Paris", "Japan": "Tokyo", "USA": "Washington D.C."}
for country, capital in capitals: # [dict-iter-missing-items]
print(f"{country} has capital {capital}.")
Good Example
capitals = {"France": "Paris", "Japan": "Tokyo", "USA": "Washington D.C."}
for country, capital in capitals.items():
print(f"{country} has capital {capital}.")

Unsupported Membership Test

Rule ID: E1135

Description: Emitted when an instance in membership test expression doesn't implement membership protocol (__contains__/__iter__/__getitem__)

Label Label

Bad Example
class Animal:
pass

dog = "dog" in Animal() # [unsupported-membership-test]
Good Example
class Animal:
ANIMALS = ["dog", "cat"]

def __contains__(self, name):
return name in self.ANIMALS

dog = "dog" in Animal()

Unsubscriptable Object

Rule ID: E1136

Description: Emitted when a subscripted value doesn't support subscription (i.e. doesn't define __getitem__ method or __class_getitem__ for a class)

Label Label

Bad Example
class Car:
pass

Car()[0] # [unsubscriptable-object]
Good Example
class Car:
def __init__(self):
self.models = ["Sedan", "SUV", "Truck"]

def __getitem__(self, idx):
return self.models[idx]

Car()[0]

Keyword Arg Before Vararg

Rule ID: W1113

Description: When defining a keyword argument before variable positional arguments, one can end up in having multiple values passed for the aforementioned parameter in case the method is called with keyword arguments

Label Label

Bad Example
def sum_values(x=None, *nums): # [keyword-arg-before-vararg]
return sum(nums) + (x if x else 0)
Good Example
def sum_values(*nums, x=None):
return sum(nums) + (x if x else 0)

Non Str Assignment To Dunder Name

Rule ID: W1115

Description: Non-string value assigned to name Emitted when a non-string value is assigned to name

Label Label

Bad Example
class Car:
pass

Car.__name__ = 100 # [non-str-assignment-to-dunder-name]
Good Example
class Car:
pass

Car.__name__ = "Sedan"

Arguments Out Of Order

Rule ID: W1114

Description: Emitted when the caller's argument names fully match the parameter names in the function signature but do not have the same order

Label Label

Bad Example
def process_args(first, second, third):
return first, second, third

def call_with_wrong_order():
first = 1
second = 2
third = 3

process_args( # [arguments-out-of-order]
first, third, second
)
Good Example
def process_args(first, second, third):
return first, second, third

def call_with_correct_order():
first = 1
second = 2
third = 3

process_args(first, second, third)

Isinstance Second Argument Not Valid Type

Rule ID: W1116

Description: Second argument of isinstance is not a type Emitted when the second argument of an isinstance call is not a type

Label Label

Bad Example
isinstance([1, 2, 3], dict) # [isinstance-second-argument-not-valid-type]
Good Example
isinstance([1, 2, 3], list)

C Extension No Member

Rule ID: I1101

Description: A variable is accessed for non-existent member of C extension. Due to unavailability of source static analysis is impossible, but it may be performed by introspecting living objects in run-time

Label Label


Unpacking Non Sequence

Rule ID: E0633

Description: Something which is not a sequence is used in an unpack assignment

Label Label

Bad Example
a, b, c = 5 # [unpacking-non-sequence]
Good Example
a, b, c = 1, 2, 3

Invalid All Object

Rule ID: E0604

Description: An invalid (non-string) object occurs in __all__

Label Label

Bad Example
__all__ = (
None, # [invalid-all-object]
Car,
Bike,
)

class Car:
pass

class Bike:
pass
Good Example
__all__ = ["Car", "Bike"]

class Car:
pass

class Bike:
pass

No Name In Module

Rule ID: E0611

Description: A name cannot be found in a module

Label Label

Bad Example
from sys import sandwich # [no-name-in-module]
Good Example
from sys import version

Undefined Variable

Rule ID: E0602

Description: An undefined variable is accessed

Label Label

Bad Example
print(speed + 5) # [undefined-variable]
Good Example
speed = 60
print(speed + 5)

Undefined All Variable

Rule ID: E0603

Description: An undefined variable name is referenced in all

Label Label

Bad Example
__all__ = ["calculate_area"] # [undefined-all-variable]

def calc_area():
pass
Good Example
__all__ = ["calc_area"]

def calc_area():
pass

Used Before Assignment

Rule ID: E0601

Description: A local variable is accessed before its assignment

Label Label

Bad Example
print(greeting) # [used-before-assignment]
greeting = "Hi there!"
Good Example
greeting = "Hi there!"
print(greeting)

Cell Var From Loop

Rule ID: W0640

Description: A variable used in a closure is defined in a loop. This will result in all closures using the same value for the closed-over variable

Label Label

Bad Example
def parent_greeting(people):
messages = []
for person in people:

def say_hi():
# do something
print(f"Hi, {person}!") # [cell-var-from-loop]

if person.isalpha():
messages.append(say_hi)

for say_hi in messages:
# the "person" variable is evaluated when the function is called here,
# which is the last value it had in the loop - "Unknown"
say_hi()


parent_greeting(["John", "Paul", "George", "Ringo"])
# "Hi, Ringo!"
# "Hi, Ringo!"
# "Hi, Ringo!"
# "Hi, Ringo!"

Global Variable Undefined

Rule ID: W0601

Description: A variable is defined through the global statement but the variable is not defined in the module scope

Label Label

Bad Example
def update_vegetable():
global VEGETABLE # [global-variable-undefined]
VEGETABLE = "potato"
Good Example
VEGETABLE = "carrot"

def update_vegetable():
global VEGETABLE
VEGETABLE = "potato"

Self Cls Assignment

Rule ID: W0642

Description: Invalid assignment to self or cls in instance or class method respectively

Label Label

Bad Example
class Vehicle:
@classmethod
def list_vehicles(cls):
cls = "car" # [self-cls-assignment]

def print_speed(self, *speeds):
self = "fast" # [self-cls-assignment]
speed = speeds[0]
print(speed)
Good Example
class Vehicle:
@classmethod
def list_vehicles(cls):
vehicle = "car"
print(vehicle)

def print_speed(self, *speeds):
speed = speeds[0]
print(speed)

Unbalanced Tuple Unpacking

Rule ID: W0632

Description: There is an unbalanced tuple unpacking in assignment

Label Label

Bad Example
colors = ("red", "green", "blue", "yellow")
red, green = colors # [unbalanced-tuple-unpacking]
Good Example
colors = ("red", "green", "blue", "yellow")
red, green, *others = colors

Possibly Unused Variable

Rule ID: W0641

Description: A variable is defined but might not be used. The possibility comes from the fact that locals() might be used, which could consume or not the said variable

Label Label

Bad Example
def choose_color(colors):
print(colors)
hue = "blue" # [possibly-unused-variable]
return locals()
Good Example
def choose_color(colors):
current_locals = locals()
print(colors)
hue = "blue"
print(hue)
return current_locals

Redefined Builtin

Rule ID: W0622

Description: A variable or function overrides a built-in

Label Label

Bad Example
def list(): # [redefined-builtin]
pass
Good Example
def list_items():
pass

Redefine In Handler

Rule ID: W0623

Description: An exception handler assigns the exception to an existing name

Label Label

Bad Example
try:
1/0
except ZeroDivisionError as e:
e = 'Error occurred' # [redefine-in-handler]
Good Example
try:
1/0
except ZeroDivisionError as err:
err = 'Error occurred'

Redefined Outer Name

Rule ID: W0621

Description: A variable's name hides a name defined in the outer scope

Label Label

Bad Example
counter = 20

def count_down(counter): # [redefined-outer-name]
for i in range(counter, 0, -1):
print(i)
Good Example
counter = 20

def count_down(limit):
for i in range(limit, 0, -1):
print(i)

Unused Import

Rule ID: W0611

Description: An imported module or variable is not used

Label Label

Bad Example
from os import getenv
from datetime import datetime # [unused-import]

API_KEY = getenv('API_KEY')
Good Example
from os import getenv

API_KEY = getenv('API_KEY')

Unused Argument

Rule ID: W0613

Description: A function or method argument is not used

Label Label

Bad Example
def area(length, width): # [unused-argument]
return length * length
Good Example
def area(length, width):
return length * width

Unused Wildcard Import

Rule ID: W0614

Description: An imported module or variable is not used from a 'from X import *' style import

Label Label

Bad Example
from collections import * # [unused-wildcard-import]

Counter(['apple', 'orange', 'banana'])
Good Example
from collections import Counter

Counter(['apple', 'orange', 'banana'])

Unused Variable

Rule ID: W0612

Description: A variable is defined but not used

Label Label

Bad Example
def greet():
first_name = "John"
last_name = "Doe" # [unused-variable]
print(f"Hello {first_name}")
Good Example
def greet():
first_name = "John"
last_name = "Doe"
print(f"Hello {first_name} {last_name}")

Global Variable Not Assigned

Rule ID: W0602

Description: A variable is defined through the global statement but no assignment to this variable is done

Label Label

Bad Example
FRUIT = "apple"

def update_fruit():
global FRUIT # [global-variable-not-assigned]
print(FRUIT)
Good Example
FRUIT = "apple"

def update_fruit():
global FRUIT
FRUIT = "banana"

Undefined Loop Variable

Rule ID: W0631

Description: A loop variable (i.e. defined by a for loop or a list comprehension or a generator expression) is used outside the loop

Label Label

Bad Example
def find_odd_number(numbers):
for x in numbers:
if x % 2 != 0:
break
return x # [undefined-loop-variable]
Good Example
def find_odd_number(numbers):
for x in numbers:
if x % 2 != 0:
return x
return None

Global Statement

Rule ID: W0603

Description: You use the global statement to update a global variable. Pylint discourages this usage, but it doesn't mean you cannot use it.

Label Label

Bad Example
num = 5

def update_num():
global num # [global-statement]
num = 15
print(num)

update_num()
print(num)
Good Example
num = 5

def update_num():
print(num)
return 15

num = update_num()
print(num)

Global At Module Level

Rule ID: W0604

Description: You use the global statement at the module level since it has no effect

Label Label

Bad Example
count = 10
global count # [global-at-module-level]
Good Example
count = 10

Security

Cyclopt scans your Python code for security vulnerabilities, injection, insecure configuration, weak cryptography, data exposure, and more. Each finding below lists its Rule ID, what it detects and how to fix it, a severity, and the relevant CWE/OWASP classification.

note

Security findings are mapped to industry classifications (CWE and OWASP).


Formatted String Bashoperator

Rule ID: formatted-string-bashoperator

Description: Building the bash_command for BashOperator via f-strings, % formatting, .format(), or + concatenation splices raw values straight into the shell command, so any variable derived from external input can inject arbitrary Bash. Pass parameters through Airflow Jinja templating (e.g. {{ params.x }} rendered by the BashOperator template engine) and quote them with shlex.quote instead of formatting the string yourself.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Attr Mutable Initializer

Rule ID: attr-mutable-initializer

Description: Assigning a literal {}, [], list(...), set(...), or dict(...) as a class attribute under @attr.s(auto_attribs=True) or @attrs.define evaluates the container exactly once at class creation, so every instance ends up sharing and mutating the same object. Replace the literal with attr.ib(factory=list) / attrs.field(factory=dict) (or the appropriate factory) so each instance receives a fresh container.

Severity Category

Dangerous Asyncio Create Exec

Rule ID: dangerous-asyncio-create-exec

Description: Arguments to asyncio.create_subprocess_exec (or asyncio.subprocess.create_subprocess_exec) are derived from the Lambda event payload, which is attacker-controlled at the API Gateway boundary. Even when the program path is fixed, an interpreted shell wrapper like sh -c $CMD re-introduces command injection (CWE-78). Build the argv list from validated literals and escape any dynamic token with shlex.quote.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Asyncio Exec

Rule ID: dangerous-asyncio-exec

Description: An event-loop transport call loop.subprocess_exec(...) is receiving an argument tainted by the Lambda event payload. Because the asyncio low-level transport spawns a child process directly, attacker-controlled tokens become command arguments and, when combined with a shell wrapper, allow OS command injection (CWE-78). Use a hard-coded executable path and pass user-supplied values only as separate, shlex.quote-wrapped argv elements.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Asyncio Shell

Rule ID: dangerous-asyncio-shell

Description: A shell-interpreted asyncio call (asyncio.create_subprocess_shell, asyncio.subprocess.create_subprocess_shell, or loop.subprocess_shell) takes its command string from the Lambda event payload. Because the entire string is forwarded to /bin/sh -c, metacharacters such as ;, |, or backticks supplied by the caller execute as additional commands (CWE-78). Switch to the argv-form create_subprocess_exec API or rebuild the command from validated constants.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Spawn Process

Rule ID: dangerous-spawn-process

Description: Process-spawning helpers from the os module (os.spawnl, os.spawnv, os.posix_spawn, os.startfile and friends) are invoked with an argument that flows from the Lambda event. These primitives execute the supplied program directly, and when used with an sh -c wrapper they expand attacker input into shell tokens, enabling command injection (CWE-78). Migrate to subprocess.run with shell=False and a list of arguments built from validated input.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Subprocess Use

Rule ID: dangerous-subprocess-use

Description: A subprocess.* call is invoked with shell=True while the command string carries data from the Lambda event payload. With shell=True the command is parsed by /bin/sh, so any shell metacharacters supplied by the caller execute arbitrary commands (CWE-78). Drop shell=True and pass the program plus arguments as a list, using shlex.split only on trusted templates and shlex.quote to wrap dynamic values.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous System Call

Rule ID: dangerous-system-call

Description: The Lambda event payload reaches a shell-backed os primitive — os.system, os.popen, or one of its popen2/3/4 variants. Each of these forwards the full command string to /bin/sh, so attacker-supplied shell metacharacters execute as additional commands (CWE-78). Replace with subprocess.run([...], shell=False) and pass dynamic values as discrete argv elements.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dynamodb Filter Injection

Rule ID: dynamodb-filter-injection

Description: A ScanFilter or QueryFilter passed to a boto3 DynamoDB Table.scan/Table.query call is constructed from the Lambda event payload. Because the filter conditions reach the DynamoDB service unchanged, an attacker can manipulate operators and attribute names to bypass intended access controls (CWE-943). Build the filter mapping explicitly from validated fields, or use boto3.dynamodb.conditions.Attr/Key expressions with parameterised values.

CWE: CWE-943 · OWASP: A01:2017

Severity Category

Mysql Sqli

Rule ID: mysql-sqli

Description: A query string passed to MySQLCursor.execute / executemany from the MySQL Connector/Python (mysql.connector) is built from the Lambda event payload. Concatenating untrusted input into SQL exposes the function to injection (CWE-89), letting attackers exfiltrate or modify rows. Use the connector's %s placeholders and pass the values as the second argument, e.g. cursor.execute("SELECT * FROM projects WHERE status = %s", (status,)).

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Psycopg Sqli

Rule ID: psycopg-sqli

Description: SQL handed to a psycopg2 cursor via execute, executemany, or mogrify is composed from the Lambda event payload. psycopg2 only escapes parameters when they are supplied as the second argument; merging them into the query string itself leaves the call open to SQL injection (CWE-89). Pass values as a tuple — for example cursor.execute("SELECT * FROM projects WHERE status = %s", (status,)) — and rely on psycopg2.sql.SQL for any dynamic identifiers.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Pymssql Sqli

Rule ID: pymssql-sqli

Description: A pymssql cursor receives a query string assembled from the Lambda event payload through cursor.execute(...). The pymssql driver only parameterises values supplied through its %s/%(name)s placeholder syntax — string concatenation reaches SQL Server verbatim and permits SQL injection (CWE-89). Refactor the call to cursor.execute("SELECT * FROM projects WHERE status = %s", (status,)).

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Pymysql Sqli

Rule ID: pymysql-sqli

Description: PyMySQL's cursor execute(...) method is invoked with a query string that flows from the Lambda event payload. PyMySQL forwards the literal SQL to MySQL whenever the values are not bound through %s placeholders, opening the door to SQL injection (CWE-89). Bind parameters instead, e.g. cursor.execute("SELECT * FROM projects WHERE status = %s", (status,)), and quote any dynamic identifier via pymysql.converters.escape_string or an allow-list.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Sqlalchemy Sqli

Rule ID: sqlalchemy-sqli

Description: A raw SQL string assembled from the Lambda event payload is being executed via SQLAlchemy's Connection.execute / Session.execute. When the SQL is not wrapped in sqlalchemy.text(...) with bound parameters, SQLAlchemy passes the string straight to the DBAPI, and attacker input can alter the query (CWE-89). Use the ORM Query API or connection.execute(text("SELECT ... WHERE status = :status"), {"status": status}).

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Tainted Code Exec

Rule ID: tainted-code-exec

Description: Python's built-in eval(...) / exec(...) interprets its argument as code, and here the expression is sourced from the Lambda event payload. That gives an external caller the ability to run arbitrary Python in the Lambda runtime (CWE-95), reading secrets, mutating state, or pivoting to other AWS APIs. Replace dynamic evaluation with ast.literal_eval, a parser, or an explicit dispatch table of allowed operations.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Tainted HTML Response

Rule ID: tainted-html-response

Description: The Lambda response body returned to API Gateway is set to a value derived from the event payload while the response advertises Content-Type: text/html. Browsers will render that body as markup, so unescaped attacker input becomes executable script (CWE-79, reflected XSS). Encode the value with html.escape(...) or, preferably, render through a templating engine (e.g. Jinja2 with autoescape) before placing it in the response.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Tainted HTML String

Rule ID: tainted-html-string

Description: HTML markup is being assembled by hand — through % formatting, str.format, + concatenation, or an f-string — with a fragment carrying data from the Lambda event. This bypasses any auto-escaping a templating engine would apply, so the resulting page lets attackers inject <script> tags (CWE-79, stored or reflected XSS). Render with a real template (e.g. Jinja2 Environment(autoescape=True)) or wrap the dynamic substring with markupsafe.escape(...).

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Tainted Pickle Deserialization

Rule ID: tainted-pickle-deserialization

Description: A deserialization sink (pickle.load(s), cPickle.load(s), _pickle.load(s), dill.load(s), or shelve.open) is fed data that ultimately originates in the Lambda event payload. The pickle protocol invokes __reduce__ constructors during unpickling, so a crafted byte stream executes arbitrary Python code in the Lambda process (CWE-502). Switch to a structured, code-free format such as JSON via json.loads, or sign the payload (e.g. HMAC) before unpickling.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Tainted SQL String

Rule ID: tainted-sql-string

Description: A SELECT/INSERT/UPDATE/DELETE-shaped literal is being concatenated with data from the Lambda event using +, %, str.format, or an f-string. Whatever DBAPI driver later receives the resulting string will execute it verbatim, allowing attacker-controlled fragments to alter the query (CWE-89). Compose queries with the driver's placeholder syntax (%s / ?) and pass user-supplied values as a separate parameter sequence — never by string interpolation.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Bokeh Deprecated Apis

Rule ID: bokeh-deprecated-apis

Description: Importing bokeh.layouts.widgetbox or bokeh.models.graphs.from_networkx references APIs that were retired in newer Bokeh releases and will raise ImportError on upgrade. Switch to bokeh.layouts.column/row for widgetbox, and bokeh.plotting.from_networkx for the graph helper, so the code stays compatible with current Bokeh versions.

Severity Category

Hardcoded Token

Rule ID: hardcoded-token

Description: A literal string is being passed as aws_access_key_id, aws_secret_access_key, or aws_session_token when constructing a boto3.client(...) / boto3.Session(...) (or a chained resource call). Embedding AWS credentials in source code exposes them to anyone who reads the repository, build artifact, or container image (CWE-798), and once leaked they cannot be rotated quickly. Load credentials from the default provider chain (IAM role, environment, or ~/.aws/credentials) or fetch them from Secrets Manager / Parameter Store at runtime.

CWE: CWE-798 · OWASP: A07:2021, A07:2025

Severity Category

Check Is None Explicitly

Rule ID: check-is-none-explicitly

Description: Guarding $X == 0 with the truthiness check $X and ... makes the whole expression unreachable because 0 is falsy in Python, so the short-circuit on the left always rejects the only value that would have satisfied the right. If the intent was to skip None while still allowing 0, compare explicitly with $X is not None and $X == 0.

Severity Category

Socket Shutdown Close

Rule ID: socket-shutdown-close

Description: Calling $SOCK.shutdown(...) followed by $SOCK.close() without a try/finally leaks the file descriptor whenever shutdown raises OSError (a common case when the peer has already closed the connection), because the subsequent close is skipped. Wrap the shutdown call in try: ... finally: $SOCK.close() so the socket is always released.

Severity Category

Suppressed Exception Handling Finally Break

Rule ID: suppressed-exception-handling-finally-break

Description: Putting a break, continue, or return inside a finally block silently discards any exception that is propagating out of the try/except and overrides any pending return value, so real errors disappear and control flow becomes very hard to reason about. Move the early exit into the try or else branch and keep finally for cleanup only.

Severity Category

Crypto Mode Without Authentication

Rule ID: crypto-mode-without-authentication

Description: Building a Cipher(...) with modes.CBC, modes.CTR, modes.CFB, or modes.OFB from cryptography.hazmat.primitives.ciphers without pairing the ciphertext with an HMAC leaves no integrity protection, exposing the construction to padding-oracle and bit-flipping attacks. Prefer an AEAD construction such as modes.GCM so encryption and authentication are produced together.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Empty Aes Key

Rule ID: empty-aes-key

Description: AES.new("", ...) is being constructed with an empty key string. AES is only secure when keyed with 16, 24, or 32 bytes of unpredictable material; an empty key effectively disables encryption and lets anyone decrypt or forge ciphertexts (CWE-327). Load a real key from a secrets store (for instance via os.urandom(32) at provisioning time stored in Secrets Manager) and reject empty values before calling AES.new.

CWE: CWE-327, CWE-310 · OWASP: A6:2017

Severity Category

Insecure Cipher Algorithm Arc4

Rule ID: insecure-cipher-algorithm-arc4

Description: cryptography.hazmat.primitives.ciphers.algorithms.ARC4 instantiates the broken RC4 stream cipher. RC4's keystream is biased in its first bytes and has been used to break TLS and WEP (CWE-327); the cryptography library exposes it only for legacy interop. Replace it with cryptography.fernet.Fernet for application-level encryption, or with AES-GCM via cryptography.hazmat.primitives.ciphers.aead.AESGCM when working at the primitive level.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Cipher Algorithm Blowfish

Rule ID: insecure-cipher-algorithm-blowfish

Description: Selecting cryptography.hazmat.primitives.ciphers.algorithms.Blowfish configures a 64-bit block cipher that is vulnerable to birthday/Sweet32 attacks after roughly 32 GiB of ciphertext under one key (CWE-327). Even Bruce Schneier, its designer, recommends moving away from it. Use cryptography.hazmat.primitives.ciphers.algorithms.AES (128/256-bit) together with an AEAD mode such as modes.GCM, or the higher-level cryptography.fernet.Fernet wrapper.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Cipher Algorithm Idea

Rule ID: insecure-cipher-algorithm-idea

Description: Building a cipher around cryptography.hazmat.primitives.ciphers.algorithms.IDEA keeps the legacy 64-bit IDEA primitive in use. The small block size makes it susceptible to Sweet32-style collision attacks, and weak-key classes further reduce its effective strength (CWE-327). Pick algorithms.AES with modes.GCM (or use cryptography.hazmat.primitives.ciphers.aead.AESGCM) for new code; reserve IDEA only for decrypting historical data that cannot be re-encrypted.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Cipher Mode ECB

Rule ID: insecure-cipher-mode-ecb

Description: Wrapping a cipher with cryptography.hazmat.primitives.ciphers.modes.ECB(...) produces deterministic, block-aligned ciphertext: identical plaintext blocks encrypt to identical ciphertext blocks, leaking structure (CWE-327) — the classic "ECB penguin" failure. Use an AEAD mode such as modes.GCM(iv) (or aead.AESGCM) and supply a fresh nonce per message so confidentiality and integrity are both protected.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Hash Algorithm MD5

Rule ID: insecure-hash-algorithm-md5

Description: Calling cryptography.hazmat.primitives.hashes.MD5() selects the MD5 digest, for which practical collision attacks have existed since 2004. Using it for fingerprints, HMAC keys, or digital signatures lets an attacker craft different inputs with the same hash (CWE-327). Switch to hashes.SHA256() (or hashes.SHA3_256() / hashes.BLAKE2b(64)); reserve MD5 only for non-security checksums such as ETag matching.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Hash Algorithm SHA1

Rule ID: insecure-hash-algorithm-sha1

Description: cryptography.hazmat.primitives.hashes.SHA1 is in use here. SHA-1 has practical collision attacks and must not be used for digital signatures, certificate fingerprints, or any integrity-critical primitive. Replace with hashes.SHA256() or hashes.SHA3_256() from the same module.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insufficient Dsa Key Size

Rule ID: insufficient-dsa-key-size

Description: The call to cryptography.hazmat.primitives.asymmetric.dsa.generate_private_key is using a key_size below 2048 bits, which falls short of the NIST SP 800-57 minimum strength. Raise the parameter to 2048 (or higher) so that the resulting DSA key is computationally resistant to factoring attacks.

CWE: CWE-326 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insufficient Ec Key Size

Rule ID: insufficient-ec-key-size

Description: Generating an EC private key with ec.SECP192R1, ec.SECT163K1, or ec.SECT163R2 via cryptography.hazmat.primitives.asymmetric.ec.generate_private_key produces a curve below the 224-bit floor recommended by NIST SP 800-57. Switch to a stronger curve such as ec.SECP256R1 or ec.SECP384R1 to retain meaningful security margin.

CWE: CWE-326 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insufficient Rsa Key Size

Rule ID: insufficient-rsa-key-size

Description: RSA keys produced through cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key with a key_size under 2048 bits are below the NIST minimum and considered factorable given modern compute. Pass key_size=2048 or larger so the generated key meets current cryptographic strength guidance.

CWE: CWE-326 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Require Encryption

Rule ID: require-encryption

Description: The Dask distributed.security.Security(...) context is being constructed with require_encryption=False, which lets the scheduler accept unencrypted worker connections and silently transmit task payloads in cleartext. Pass require_encryption=True so the cluster refuses non-TLS endpoints.

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Access Foreign Keys

Rule ID: access-foreign-keys

Description: Reading $X.user.id triggers an additional SELECT on the related User row just to fetch the primary key the ORM already stores locally. Use the foreign-key column directly with $X.user_id to read the value from the existing instance without round-tripping to the database.

Severity Category

Avoid Insecure Deserialization

Rule ID: avoid-insecure-deserialization

Description: Deserialising request-controlled bytes through pickle.load(s), _pickle, cPickle, shelve, dill, or yaml.load (without SafeLoader) reconstructs arbitrary Python objects and can execute attacker-supplied gadgets, yielding remote code execution inside the Django process. Parse untrusted input with json instead, or use yaml.safe_load and explicit Dumper=yaml.SafeDumper / Loader=yaml.SafeLoader arguments.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Avoid Mark Safe

Rule ID: avoid-mark-safe

Description: Wrapping a dynamic value in django.utils.safestring.mark_safe(...) flags the resulting string as already-escaped, so the template engine renders it verbatim and any attacker-influenced characters become live HTML — a classic XSS sink. Build markup with django.utils.html.format_html(...), which auto-escapes interpolated arguments while keeping the surrounding template static.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Avoid Query Set Extra

Rule ID: avoid-query-set-extra

Description: Calling QuerySet.extra(...) lets the caller splice raw SQL fragments into where, tables, select, and order_by, none of which Django escapes — the Django team itself recommends avoiding this API for exactly that reason. Rewrite the query with ORM methods like filter(...), annotate(...), or Func expressions; if .extra is unavoidable, keep dynamic values inside the params=[...] argument with %s placeholders.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Avoid Raw SQL

Rule ID: avoid-raw-sql

Description: Building a query with Model.objects.raw(...) or django.db.models.expressions.RawSQL(...) from a non-literal string skips the ORM's parameter binding, so any concatenated user value is injected straight into the executed SQL. Express the query through the ORM (filter, annotate, Q, F) or pass the dynamic data via the params=[...] argument with %s placeholders instead of embedding it in the SQL text.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Class Extends Safestring

Rule ID: class-extends-safestring

Description: Subclassing django.utils.safestring.SafeString, SafeText, or SafeData produces a type that the template autoescaper unconditionally treats as already-safe HTML, so every instance — including ones built from user data — is rendered without escaping. Drop the subclass and, where literal HTML is genuinely required, call mark_safe(...) on a known-static string built with format_html(...).

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Command Injection OS System

Rule ID: command-injection-os-system

Description: Untrusted data from a Django 'request' reaches 'os.system', which runs the string through '/bin/sh' and lets shell metacharacters (';', '|', '' ' '', '$()') start additional commands. The result is OS command injection executed as the application user. Replace the call with 'subprocess.run([...], shell=False)' and pass arguments as a list of separate tokens drawn from a validated allow-list.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Context Autoescape Off

Rule ID: context-autoescape-off

Description: Constructing a django.template.Context (or a backend-options dict) with "autoescape": False turns off HTML escaping for every variable rendered through that context, so any user-controlled value flowing into {{ ... }} is interpreted as live HTML. Remove the autoescape: False entry — or set it back to True — and use the |safe filter or mark_safe(...) only for the specific values that genuinely need it.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Csv Writer Injection

Rule ID: csv-writer-injection

Description: Request data flows into csv.writer.writerow / writerows / writeheader without neutralising leading =, +, -, @ characters. When the exported CSV is opened in Excel, LibreOffice or Google Sheets, those values are interpreted as formulas and can exfiltrate data or run attacker-controlled code on the recipient's machine (CSV / formula injection). Use defusedcsv.writer as a drop-in replacement or prefix untrusted cells with a single quote before writing.

CWE: CWE-1236 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Custom Expression As SQL

Rule ID: custom-expression-as-sql

Description: Implementing or calling as_sql(...) on a Django ORM expression bypasses the parameterised compiler and lets the author splice raw fragments straight into the generated query. If any user-controlled value reaches $EXPRESSION.as_sql, the application becomes vulnerable to SQL injection — review the implementation and return SQL placeholders plus a params tuple rather than concatenating strings.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Debug Template Tag

Rule ID: debug-template-tag

Description: The {% debug %} template tag prints the current context dictionary and the list of loaded modules whenever DEBUG = True, leaking variable names, settings, and stack-related metadata directly into the rendered page. Delete the tag from the template — debugging context belongs in the Django Debug Toolbar or in logs, never in user-facing markup.

CWE: CWE-489 · OWASP: A06:2017

Severity Category

Direct Use Of Httpresponse

Rule ID: direct-use-of-httpresponse

Description: Returning dynamic content through django.http.HttpResponse(...) (or its HttpResponseBadRequest, HttpResponseNotFound, etc. variants) with a text/html body sends the payload to the browser without passing through the template autoescaper, so any embedded user data is rendered as raw HTML. Render through django.shortcuts.render(request, "template.html", {...}) so Django escapes interpolated variables automatically.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Django DB Model Save Super

Rule ID: django-db-model-save-super

Description: Overriding save() on the Django model $MODEL without invoking super().save(...) skips the inherited persistence logic, so the row is never written and field defaults, signals, and auto-now timestamps are bypassed. Call super().save(*args, **kwargs) (or super($MODEL, self).save(...)) inside the override so the ORM still commits the instance.

Severity Category

Django No CSRF Token

Rule ID: django-no-csrf-token

Description: This state-changing HTML <form> (POST/PUT/PATCH/DELETE) omits the {% csrf_token %} tag, leaving the endpoint open to cross-site request forgery. Without the token Django's CsrfViewMiddleware will reject legitimate submissions and any view bypassing the middleware accepts requests forged from another origin. Insert {% csrf_token %} inside the form body.

CWE: CWE-352

Severity Category

Rule ID: django-secure-set-cookie

Description: Calling response.set_cookie(...) without secure=True, httponly=True, and samesite="Lax" (or "Strict") leaves the cookie reachable from JavaScript, transmittable over plain HTTP, and attachable to cross-site requests — common preconditions for session hijacking and CSRF. Pass the three flags explicitly, and only relax one when the cookie demonstrably requires that capability.

CWE: CWE-614 · OWASP: A05:2021, A02:2025

Severity Category

Django Using Request Post After Is Valid

Rule ID: django-using-request-post-after-is-valid

Description: After $FORM.is_valid() succeeds, reading from request.POST skips the type coercion and validation that the form just performed and re-exposes raw, untrusted strings. Switch to $FORM.cleaned_data["field"], which returns the sanitized, correctly-typed values produced by each field's clean() method.

CWE: CWE-20

Severity Category

Extends Custom Expression

Rule ID: extends-custom-expression

Description: Subclassing internal Django ORM expression types such as Func, Expression, RawSQL, Subquery, or Case (in $CLASS) requires overriding the SQL compilation phase, which is an unparameterised seam in the ORM. If user input reaches the overridden as_sql, template, or arg_joiner logic, the resulting query becomes injectable — keep dynamic values in the params list and never f-string them into the SQL template.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Filter With Is Safe

Rule ID: filter-with-is-safe

Description: Registering a custom template filter with @register.filter(is_safe=True) promises Django that the filter neither introduces nor removes HTML-significant characters, so the engine emits its return value without escaping. If the filter appends, modifies, or formats any of its arguments — particularly anything originating from request data — that promise is broken and a stored XSS is introduced. Drop is_safe=True and call mark_safe(format_html(...)) on a known-safe literal only when truly necessary.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Formathtml Fstring Parameter

Rule ID: formathtml-fstring-parameter

Description: Pre-interpolating values into the first argument of django.utils.html.format_html(...) — via f-strings, % formatting, or str.format — bypasses the per-argument escaping that format_html is designed to perform, because the interpolated characters arrive already baked into the "static" template. Keep the first argument a literal string with {} placeholders and pass user-controlled values as the remaining positional arguments so they are escaped before substitution.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Global Autoescape Off

Rule ID: global-autoescape-off

Description: Setting "autoescape": False inside the OPTIONS of the TEMPLATES backend in settings.py disables HTML escaping for every template the project renders, so a single unescaped variable anywhere in the codebase becomes a site-wide XSS. Restore "autoescape": True (the Django default) and opt out per-block with {% autoescape off %} or per-value with mark_safe(...) only where the content is provably static.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Globals As Template Context

Rule ID: globals-as-template-context

Description: Passing globals() to django.shortcuts.render or Template.render hands every module-level name (including imported callables and settings) to the template engine. A crafted template path or attribute lookup can then invoke arbitrary functions, opening a server-side template injection (SSTI) hole. Build an explicit context dictionary such as {"user": user, "items": items} and pass that instead.

CWE: CWE-96 · OWASP: A03:2021, A05:2025

Severity Category

Globals Misuse Code Execution

Rule ID: globals-misuse-code-execution

Description: A value pulled from request.GET / request.POST indexes globals() and the resulting object is then invoked, letting a client choose which module-level callable the view executes. This is a direct remote code execution path. Replace the dynamic lookup with an explicit allow-list such as dispatch = {"create": create_item, "delete": delete_item} and only call dispatch[name] after validating the key.

CWE: CWE-96 · OWASP: A03:2021, A05:2025

Severity Category

Hashids With Django Secret

Rule ID: hashids-with-django-secret

Description: Seeding hashids.Hashids with django.conf.settings.SECRET_KEY reuses the framework's master secret as a reversible obfuscation salt. The Hashids algorithm is not cryptographically secure: given enough emitted IDs an attacker can recover the salt and therefore your SECRET_KEY, which is used to sign sessions, password resets and CSRF tokens. Derive a separate, dedicated salt for Hashids and rotate SECRET_KEY if it was leaked this way.

CWE: CWE-327 · OWASP: A02:2021

Severity Category

HTML Magic Method

Rule ID: html-magic-method

Description: Implementing a __html__ magic method on a class signals to conditional_escape and the Django template engine that the object already produces escape-safe HTML, so its rendered output skips autoescaping. If the returned string is built from user input, attacker payloads land in the page unescaped — favour explicit mark_safe(format_html(...)) calls at the rendering site so the safe boundary is visible in code review.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

HTML Safe

Rule ID: html-safe

Description: Applying @django.utils.html.html_safe to a class auto-injects an __html__ method that returns str(self), which causes Django's template engine to render every instance without HTML escaping. Any field or attribute that contributes to __str__ becomes a potential XSS sink — prefer constructing a single mark_safe(format_html(...)) value at render time rather than marking an entire class as HTML-safe.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Locals As Template Context

Rule ID: locals-as-template-context

Description: locals() is forwarded as the rendering context for django.shortcuts.render or Template.render, leaking every name that happens to be in scope, including form objects, database rows, and transient secrets. Beyond data exposure, a template that references a callable from that scope can be coaxed into server-side template injection. Build an explicit context dict containing only the values the template needs (e.g. {"profile": profile}).

CWE: CWE-96 · OWASP: A03:2021, A05:2025

Severity Category

Mass Assignment

Rule ID: mass-assignment

Description: Expanding request.POST / request.GET with ** into Model.objects.create or an instance update() lets a caller set any model attribute, including sensitive ones such as is_staff, is_superuser, or foreign keys to other users' records. This is a textbook mass-assignment vulnerability. Bind each field explicitly (Model(name=form.cleaned_data["name"], ...)) or use a ModelForm / DRF Serializer with a restrictive fields list.

CWE: CWE-915 · OWASP: A08:2021, A08:2025

Severity Category

Missing Throttle Config

Rule ID: missing-throttle-config

Description: The REST_FRAMEWORK settings dictionary defines no DEFAULT_THROTTLE_CLASSES / DEFAULT_THROTTLE_RATES, so every DRF endpoint accepts unlimited requests per client. Without throttling, attackers can drive expensive views into resource exhaustion or brute-force authentication. Register at least one throttle class (e.g. AnonRateThrottle, UserRateThrottle) and matching rates such as {"anon": "100/hour", "user": "1000/hour"}.

CWE: CWE-770 · OWASP: A05:2021, A06:2017, A02:2025

Severity Category

Nan Injection

Rule ID: nan-injection

Description: Request-supplied strings are cast directly through float(...), bool(...), or complex(...). Submitting the literal "nan" (or any capitalisation, plus inf/-inf) yields IEEE-754 special values that silently break comparisons - nan > x and nan < x are both False, bool("nan") is True - and can flip authorisation or pricing checks. Validate the string against a numeric regex first, or use int(...) with explicit range checks where you expect integers.

CWE: CWE-704

Severity Category

No CSRF Exempt

Rule ID: no-csrf-exempt

Description: Decorating a view with @django.views.decorators.csrf.csrf_exempt removes Django's CSRF middleware protection from that endpoint, allowing a malicious site to submit authenticated state-changing requests on behalf of the logged-in user. Remove the decorator and keep the standard CsrfViewMiddleware, or — if the endpoint really must accept cross-origin calls — protect it with a signed token or proper CORS plus origin validation.

CWE: CWE-352 · OWASP: A01:2021, A01:2025

Severity Category

No Null String Field

Rule ID: no-null-string-field

Description: Setting null=True on a CharField or TextField creates two distinct "empty" values in the database — NULL and "" — which complicates queries and breaks Django's own convention of storing missing strings as empty. Drop null=True from string fields and rely on the empty string as the single "no data" representation.

Severity Category

Nontext Field Must Set Null True

Rule ID: nontext-field-must-set-null-true

Description: Declaring blank=True on a non-text Django model field without null=True lets forms accept an empty value but leaves the database column NOT NULL, so saving blank data raises IntegrityError. For numeric, boolean, date, and foreign-key fields the Django convention is to allow NULL at the DB layer — add null=True alongside blank=True.

Severity Category

Open Redirect

Rule ID: open-redirect

Description: The URL passed to django.shortcuts.redirect (or HttpResponseRedirect) originates from the request without first being validated by django.utils.http.url_has_allowed_host_and_scheme (or the legacy is_safe_url). An attacker can craft a link such as ?next=https://evil.example.com to bounce the victim off your domain for phishing. Validate the candidate URL against an allow-list of hosts before redirecting, or redirect to a named route.

CWE: CWE-601 · OWASP: A01:2021, A01:2025

Severity Category

Password Empty String

Rule ID: password-empty-string

Description: $MODEL.set_password($VAR) is being called with the empty string and the user is then saved, producing a real, hashed password that any caller can log in with by submitting "". To mark the account as unable to authenticate via password, call $MODEL.set_unusable_password() (or pass None to set_password) before save() so the stored hash is rejected by Django's authentication backend.

CWE: CWE-521 · OWASP: A07:2021, A07:2025

Severity Category

Path Traversal File Name

Rule ID: path-traversal-file-name

Description: A request value is interpolated into a filename template ending in .log, .zip, .txt, .csv, .xml, or .html via % or str.format, and the resulting string is later passed to a filesystem sink. Path components such as ../../etc/passwd will escape the intended directory and disclose or overwrite arbitrary files. Constrain the input to a basename, anchor it under a known root, and verify with os.path.realpath(path).startswith(root).

CWE: CWE-22 · OWASP: A05:2017, A01:2021, A01:2025

Severity Category

Path Traversal Join

Rule ID: path-traversal-join

Description: Request-derived input is concatenated by os.path.join(...) and the resulting path is opened with open(...). os.path.join does not sanitize traversal sequences and silently discards earlier components when given an absolute path, so a value like ../../secrets.env reaches the filesystem unchanged. Canonicalize the joined path with os.path.realpath(...) and reject anything outside the allowed root, or use pathlib.Path.resolve() plus an is_relative_to(...) check.

CWE: CWE-22 · OWASP: A05:2017, A01:2021, A01:2025

Severity Category

Path Traversal Open

Rule ID: path-traversal-open

Description: The path argument of the built-in open(...) (including the with open(...) context-manager form) comes straight from a Django request, either directly or via %, str.format, f-string, or concatenation. A caller supplying ../../etc/passwd reads arbitrary files; in write mode they can overwrite source or configuration files. Normalize with os.path.realpath(...) (or pathlib.Path.resolve()) and ensure the final path stays within a fixed allow-listed directory.

CWE: CWE-22 · OWASP: A05:2017, A01:2021, A01:2025

Severity Category

Raw HTML Format

Rule ID: raw-html-format

Description: A literal HTML string containing an opening tag (<div ..., <a ..., etc.) is composed with %, str.format, +, or an f-string from values pulled off the request object, bypassing Django's template autoescaping. Any unescaped attribute or text segment becomes a cross-site scripting vector. Render through django.shortcuts.render(...) with a proper template, or wrap each fragment in django.utils.html.escape(...) (or use format_html(...)) before concatenation.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Reflected Data Httpresponse

Rule ID: reflected-data-httpresponse

Description: Request data is echoed straight into the body of django.http.HttpResponse, so the browser interprets whatever the caller submits as HTML. This classic reflected XSS lets an attacker run JavaScript in the victim's session and steal cookies, CSRF tokens, or DOM contents. Render the response through a template (render(request, ...)) so autoescaping kicks in, or escape the value first with django.utils.html.escape(...).

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Reflected Data Httpresponsebadrequest

Rule ID: reflected-data-httpresponsebadrequest

Description: The 400 error body returned by django.http.HttpResponseBadRequest embeds untrusted request data without escaping, so an attacker can craft a URL or payload that triggers the error path and reflects HTML/JavaScript back to the victim. Even error responses are rendered by the browser, so this is still reflected XSS. Escape the value with django.utils.html.escape(...) or return a templated error page instead.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Request Data Fileresponse

Rule ID: request-data-fileresponse

Description: django.http.FileResponse receives a file handle (or path) derived from a request parameter, letting a client choose which file the server streams back. Traversal payloads such as ../../etc/passwd will reach open(...) unchanged and exfiltrate arbitrary files. Look the requested item up by primary key in a FileField model and call default_storage.open(...) on the stored relative path, or validate with os.path.realpath(...) against a fixed root directory.

CWE: CWE-22 · OWASP: A05:2017, A01:2021, A01:2025

Severity Category

Request Data Write

Rule ID: request-data-write

Description: Untrusted request data is streamed into a file-like object's .write(...) method, allowing an attacker to inject CRLF sequences (forging extra log entries), corrupt structured files, or exhaust disk space and trigger a denial-of-service. Strip newlines and control characters, cap the byte length you accept, and write through a structured serializer (e.g. json.dumps) rather than concatenating untrusted strings.

CWE: CWE-93 · OWASP: A03:2021, A05:2025

Severity Category

SQL Injection DB Cursor Execute

Rule ID: sql-injection-db-cursor-execute

Description: The SQL string handed to cursor.execute(...) is built from request data using %, str.format, f-string, or +, instead of bound parameters. Whatever the client sends becomes part of the query, enabling classic SQL injection against the connection opened by django.db.connection.cursor(). Always supply the query as a literal with %s placeholders and pass a tuple/list of values as the second argument: cursor.execute("SELECT ... WHERE id = %s", [user_id]).

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

SQL Injection Using Extra Where

Rule ID: sql-injection-using-extra-where

Description: A request value is interpolated into the where=[...] argument of $MODEL.objects.extra(...), so the attacker controls a fragment of raw SQL that Django pastes verbatim into the generated query. This bypasses every protection of the ORM and yields SQL injection. Replace extra(where=[...]) with proper ORM lookups such as $MODEL.objects.filter(field=value), or, if extra is unavoidable, use %s placeholders and pass values via the params= argument.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

SQL Injection Using Raw

Rule ID: sql-injection-using-raw

Description: $MODEL.objects.raw(...) is called with a SQL string that already contains request-derived data, so the manager has no chance to parameterise it before running the query on the database backend. This is a SQL injection sink. Move filter logic to a regular QuerySet such as $MODEL.objects.filter(field=value), or supply placeholders and pass user values via the params=[...] argument of raw().

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

SQL Injection Using Rawsql

Rule ID: sql-injection-using-rawsql

Description: Untrusted request data is concatenated into the SQL string handed to django.db.models.expressions.RawSQL(...), leaving the column expression fully attacker-controlled. The injected fragment will be executed inside every annotated query that uses this expression. Pass values through the second positional params argument as a list of bound parameters and keep only %s placeholders in the SQL literal.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

SSRF Injection Requests

Rule ID: ssrf-injection-requests

Description: The URL passed to requests.get / requests.post (or any other requests.$METHOD(...) call) is assembled from data on the current Django request. A caller can therefore force the server to fetch internal addresses such as http://169.254.169.254/ (cloud metadata), http://localhost:5984/, or other intranet hosts, exfiltrating credentials and bypassing firewall boundaries (SSRF). Parse the URL, validate the scheme and host against a fixed allow-list, and refuse private IP ranges before issuing the outbound request.

CWE: CWE-918 · OWASP: A10:2021, A01:2025

Severity Category

SSRF Injection Urllib

Rule ID: ssrf-injection-urllib

Description: urllib.request.urlopen(...) is invoked with a URL containing request-derived data, so the standard-library HTTP client is steered to any address the attacker supplies. Unlike requests, urlopen also honours the file://, ftp://, and gopher:// schemes, broadening the SSRF impact to local file disclosure. Validate the parsed URL against a scheme/host allow-list (only http/https, only approved domains) before opening it, and refuse responses from RFC1918 addresses.

CWE: CWE-918 · OWASP: A10:2021, A01:2025

Severity Category

String Field Must Set Null True

Rule ID: string-field-must-set-null-true

Description: When a CharField or TextField combines unique=True with blank=True but omits null=True, every blank submission stores "" and the second blank row violates the unique constraint. Add null=True so empty inputs are persisted as NULL, which UNIQUE treats as distinct values.

Severity Category

Subprocess Injection

Rule ID: subprocess-injection

Description: A taint path connects the Django request object to a subprocess.* call that runs either a dynamically-built command line or one whose first element is a shell (sh, bash, zsh) or interpreter (python). Attacker-supplied arguments can therefore start additional commands and achieve remote code execution. Build the argv list from fixed string literals and map user input to one of a small set of pre-approved operations selected from a dictionary.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Tainted SQL String

Rule ID: tainted-sql-string

Description: A string literal beginning with a SQL keyword (SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP) is concatenated, formatted, or f-stringed with values that taint analysis traces back to the Django request. Whatever sink eventually receives this string (cursor execute, raw, RawSQL, ...) will run attacker-controlled SQL. Prefer Django's ORM (Model.objects.filter(...)); when raw SQL is unavoidable, keep %s placeholders in the literal and pass values through params=[...].

CWE: CWE-915 · OWASP: A08:2021, A08:2025

Severity Category

Tainted URL Host

Rule ID: tainted-url-host

Description: Request data flows into the host segment of a URL being assembled via %, str.format, +=, or an f-string (the literal ends with ://). Whoever calls the view chooses the target server of any subsequent outbound request, enabling SSRF as well as credential leakage if cookies or Authorization headers are forwarded. Hard-code the host or resolve it through a whitelist keyed by an internal identifier rather than concatenating user input directly.

CWE: CWE-918 · OWASP: A10:2021, A01:2025

Severity Category

Template Autoescape Off

Rule ID: template-autoescape-off

Description: Autoescaping is turned off inside this {% autoescape off %} block, so every variable rendered between the tags is emitted as raw HTML. Any user-controlled value passing through here becomes a cross-site scripting (XSS) sink. Remove the directive and rely on Django's default escaping, or constrain trusted strings with mark_safe in the view instead.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Template Blocktranslate No Escape

Rule ID: template-blocktranslate-no-escape

Description: Output emitted by {% blocktranslate %} / {% blocktrans %} bypasses HTML escaping, so a translator (or anyone editing the .po catalog) can inject <script> tags that execute in users' browsers. Wrap the block in {% filter force_escape %} or apply |force_escape to each interpolated placeholder so translated content is treated as untrusted text.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Template Translate As No Escape

Rule ID: template-translate-as-no-escape

Description: A translation captured via {% translate ... as VAR %} (or its {% trans %} alias) is later rendered with {{ VAR }} without escaping, so malicious markup inserted by a translator will execute in the browser. Pipe the variable through |force_escape at the render site, or wrap the output in a {% filter force_escape %} block to neutralize translated HTML.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Template Var Unescaped With Safeseq

Rule ID: template-var-unescaped-with-safeseq

Description: Applying the |safeseq filter marks every item of an iterable as safe HTML, so each element is rendered verbatim without escaping. Should any element originate from user input, the template becomes a cross-site scripting (XSS) vector. Drop the filter and let Django escape items by default, or sanitize trusted strings server-side with mark_safe before rendering.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Unvalidated Password

Rule ID: unvalidated-password

Description: Invoking $MODEL.set_password(...) without first running django.contrib.auth.password_validation.validate_password(...) lets weak, common, or numeric-only credentials reach the user store, defeating the password policies configured in AUTH_PASSWORD_VALIDATORS. Validate the new password (passing the user instance so similarity checks can run) before persisting it, and propagate any ValidationError back to the caller.

CWE: CWE-521 · OWASP: A07:2021, A07:2025

Severity Category

Use Count Method

Rule ID: use-count-method

Description: Counting rows by calling .len() on a QuerySet forces Django to evaluate the query, fetch every matching row, and instantiate model objects in Python just to measure the list. Use QuerySet.count() instead so the database returns a single SELECT COUNT(*) value without hydrating any objects.

Severity Category

Use Decimalfield For Money

Rule ID: use-decimalfield-for-money

Description: Storing monetary value $F in a FloatField introduces binary floating-point rounding errors that accumulate across arithmetic and aggregation, producing incorrect totals and ledger discrepancies. Replace FloatField with DecimalField(max_digits=..., decimal_places=...) so currency is stored as exact base-10 numbers.

Severity Category

Use Earliest Or Latest

Rule ID: use-earliest-or-latest

Description: Combining QuerySet.order_by(...) with [0] instructs the database to sort the full result set and then materialise it just to read the first row, which is wasteful and easy to misread. Switch to QuerySet.earliest("field") or QuerySet.latest("field"), which emit a single-row query and convey intent.

Severity Category

Use None For Password Default

Rule ID: use-none-for-password-default

Description: The argument feeding $MODEL.set_password(...) defaults to "" - either as a function parameter default or as the fallback value of request.GET.get(..., "") - so whenever the caller omits a password Django hashes the empty string and stores it as a valid credential. Use None (or omit the fallback so a missing field raises an error) and call $MODEL.set_unusable_password() when you explicitly want to disable password authentication.

CWE: CWE-521 · OWASP: A07:2021, A07:2025

Severity Category

User Eval

Rule ID: user-eval

Description: A value taken straight from the Django request object is passed to eval, which executes it as a Python expression and grants the caller arbitrary code execution under the server process. There is no safe way to sandbox eval against attacker-controlled input. Parse the value explicitly with int(...), decimal.Decimal(...), or ast.literal_eval, depending on what the field is supposed to contain.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

User Eval Format String

Rule ID: user-eval-format-string

Description: Request data is woven into a formatted string (%, str.format, or f-string) and then handed to eval, so an attacker controls part of the Python expression being evaluated. Even with surrounding literal text the injected value can close the expression and run arbitrary code. Drop eval entirely and use ast.literal_eval for safe literals or a parser tailored to the input you expect.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

User Exec

Rule ID: user-exec

Description: Request data flows directly into exec (sometimes via loop.run_in_executor(None, exec, ...) for async views), letting a caller execute arbitrary Python statements with the privileges of the Django process. exec cannot be safely sandboxed against untrusted input. Eliminate it and route the requested behaviour through declared view functions selected by an explicit mapping.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

User Exec Format String

Rule ID: user-exec-format-string

Description: A request-derived value (optionally decoded through base64.decodestring) is concatenated via %, str.format, or an f-string and then passed to exec, which runs the resulting text as a full Python statement block. The base64 wrapping provides no protection: it merely obfuscates the payload before execution. Remove the exec call and dispatch to vetted Python functions chosen by a strict allow-list.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

XSS HTML Email Body

Rule ID: xss-html-email-body

Description: A request value is used as the body of a django.core.mail.EmailMessage whose content_subtype is set to "html", so any HTML or JavaScript the client provides is delivered to the recipient as live markup. Mail clients that render HTML will execute embedded scripts (XSS) or reveal exfiltration payloads. Render the body through a Django template with autoescaping on, or sanitize the input with bleach.clean(...) before assigning it.

CWE: CWE-74 · OWASP: A03:2021, A05:2025

Severity Category

XSS Send Mail HTML Message

Rule ID: xss-send-mail-html-message

Description: django.core.mail.send_mail is called with the html_message= keyword bound to data taken from the current request, so an attacker can supply the HTML body of the outbound email. Mail clients that render HTML will execute scripts, fetch tracking pixels, or display spoofed UI to the recipient. Build the HTML payload from a trusted template via render_to_string, or escape user-controlled fragments before interpolating them.

CWE: CWE-74 · OWASP: A03:2021, A05:2025

Severity Category

Docker Arbitrary Container Run

Rule ID: docker-arbitrary-container-run

Description: A non-literal image name is being passed to docker.client.containers.run(...) or containers.create(...) on a DockerClient / docker.from_env() handle. If the image identifier originates from user input, an attacker can pull and launch an arbitrary container, effectively gaining code execution on the host. Pin container images to a vetted allowlist of constant references.

CWE: CWE-250

Severity Category

Wildcard CORS

Rule ID: wildcard-cors

Description: Permissive CORSMiddleware(allow_origins=["*"]) configuration grants any origin permission to call this FastAPI app, which exposes authenticated endpoints to cross-site attacks. Replace the wildcard with an explicit allowlist of trusted origins so browsers enforce same-origin restrictions properly.

CWE: CWE-942 · OWASP: A05:2021, A02:2025

Severity Category

Avoid App Run With Bad Host

Rule ID: avoid_app_run_with_bad_host

Description: Binding the Flask development server to 0.0.0.0 via app.run(host="0.0.0.0") makes it reachable on every network interface, including public ones. Bind to a specific internal address (e.g. 127.0.0.1) for local development, and put production traffic behind a real WSGI server such as gunicorn or uWSGI.

CWE: CWE-668 · OWASP: A01:2021, A01:2025

Severity Category

Avoid Hardcoded Config DEBUG

Rule ID: avoid_hardcoded_config_DEBUG

Description: Pinning app.config["DEBUG"] in source code can leave the Werkzeug debugger turned on in production, exposing an interactive Python REPL over tracebacks. Read the value from the FLASK_DEBUG environment variable instead so it can be safely toggled per deployment.

CWE: CWE-489 · OWASP: A05:2021, A02:2025

Severity Category

Avoid Hardcoded Config ENV

Rule ID: avoid_hardcoded_config_ENV

Description: The Flask ENV setting controls debug, error handling, and middleware selection, so pinning it to "development" or "production" in code couples the environment to a specific deployment. Drive it from the standard FLASK_ENV environment variable so the same artifact can run in any environment.

CWE: CWE-489 · OWASP: A05:2021, A02:2025

Severity Category

Avoid Hardcoded Config SECRET KEY

Rule ID: avoid_hardcoded_config_SECRET_KEY

Description: Embedding a literal SECRET_KEY in app.config checks the session-signing secret into version control, allowing anyone with repo access to forge Flask session cookies and CSRF tokens. Load SECRET_KEY from an environment variable or secret manager and rotate the leaked value immediately.

CWE: CWE-489 · OWASP: A05:2021, A02:2025

Severity Category

Avoid Hardcoded Config TESTING

Rule ID: avoid_hardcoded_config_TESTING

Description: Hardcoding TESTING in app.config baked the testing flag into source control, which can ship test-only behaviour to production or vice versa. Source the value from a FLASK_TESTING environment variable or a config object loaded via Flask.config.from_envvar instead.

CWE: CWE-489 · OWASP: A05:2021, A02:2025

Severity Category

Avoid Send File Without Path Sanitization

Rule ID: avoid_send_file_without_path_sanitization

Description: A route parameter named filename is being passed directly to flask.send_file(...), so an attacker can request ../../etc/passwd (or any other host file) and read it through the response. Use flask.send_from_directory(safe_base, filename) which performs the path-confinement check, and validate the filename component first.

CWE: CWE-73 · OWASP: A04:2021, A06:2025

Severity Category

Avoid Using App Run Directly

Rule ID: avoid_using_app_run_directly

Description: Calling app.run(...) at module top level executes whenever the module is imported (e.g. by a WSGI server), which can spawn the development server in production. Wrap it inside if __name__ == "__main__": or a function so it only runs when the script is invoked directly.

CWE: CWE-668 · OWASP: A01:2021, A01:2025

Severity Category

Avoid Accessing Request In Wrong Handler

Rule ID: avoid-accessing-request-in-wrong-handler

Description: Reading flask.request.json, flask.request.form, or flask.request.data inside a GET route handler will raise at runtime because GET requests have no body. Move the body access to a handler bound to POST/PUT/etc., or use flask.request.args for query-string parameters.

Severity Category

Csv Writer Injection

Rule ID: csv-writer-injection

Description: Values taken from flask.request.* (forms, args, headers, JSON body or route variables) flow into csv.writer().writerow(...)/writerows(...) without sanitisation. When opened in a spreadsheet, fields starting with =, +, -, @ are interpreted as formulas, enabling CSV/formula injection. Prefix risky leading characters with a single quote or switch to the drop-in defusedcsv writer.

CWE: CWE-1236 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Template String

Rule ID: dangerous-template-string

Description: A string built through .format(), %, +=, or an f-string is being passed to flask.render_template_string(...). Because the template source itself is dynamic, anything embedded in it is interpreted by Jinja2 and can lead to server-side template injection (SSTI) or stored XSS. Move the template to a static file rendered with flask.render_template() and pass only the variable values as context.

CWE: CWE-96 · OWASP: A03:2021, A05:2025

Severity Category

Debug Enabled

Rule ID: debug-enabled

Description: Starting Flask with app.run(debug=True) enables the Werkzeug interactive debugger, which exposes a remote Python REPL on tracebacks and leaks stack frames to the browser. Read the flag from FLASK_DEBUG or a config object so production deployments stay disabled.

CWE: CWE-489 · OWASP: A06:2017

Severity Category

Direct Use Of Jinja2

Rule ID: direct-use-of-jinja2

Description: Rendering through raw jinja2.Environment or jinja2.Template.render(...) skips the safe defaults that Flask applies on top of Jinja2, leaving the response open to cross-site scripting whenever a template variable carries untrusted data. Route HTML generation through flask.render_template(...) with a .html file so autoescaping stays on by extension.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Directly Returned Format String

Rule ID: directly-returned-format-string

Description: Returning an f-string, .format() result, % interpolation, or string concatenation from a Flask view sends raw HTML to the browser without autoescaping. If any taint from flask.request reaches the formatted value, it becomes a stored or reflected XSS sink. Render through flask.render_template() with .html templates so Jinja escapes the interpolated values.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Eval Injection

Rule ID: eval-injection

Description: Tainted data from flask.request.* reaches eval(...), which evaluates the value as a Python expression and gives the caller direct remote code execution on the server. Remove the eval call entirely; if structured input is required, parse it with ast.literal_eval or json.loads.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Exec Injection

Rule ID: exec-injection

Description: flask.request data is passed to exec(...), which runs the argument as arbitrary Python statements - the attacker effectively gains full code execution on the server. Drop the exec call; switch to data-driven dispatch (e.g. a function lookup keyed on a validated string) when runtime behaviour really must depend on the request.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Explicit Unescape With Markup

Rule ID: explicit-unescape-with-markup

Description: Wrapping a dynamic value with flask.Markup(...) (or calling .unescape() on a Markup instance) tells Jinja2 the string is already safe and disables HTML escaping for that fragment, which becomes XSS the moment the value is influenced by a user. Confirm the argument is a hard-coded literal, otherwise drop the Markup wrapper and let autoescaping handle the content.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Flask API Method String Format

Rule ID: flask-api-method-string-format

Description: The Flask-RESTful controller $CLASS.$METHOD formats argument $ARG directly into the URL passed to requests.$REQMETHOD(...), letting a client steer the outbound HTTP call. Validate $ARG against a strict allowlist or pass dynamic data through params=/json= instead of interpolating it into the URL string.

CWE: CWE-134

Severity Category

Flask Cache Query String

Rule ID: flask-cache-query-string

Description: Decorating a handler that reads request.args with @cache.cached(...) without query_string=True will return stale responses because Flask-Caching ignores the query string by default. Additionally, mutating verbs (POST, PUT, DELETE, PATCH) should never be cached. Pass query_string=True and restrict caching to safe HTTP methods.

Severity Category

Flask CORS Misconfiguration

Rule ID: flask-cors-misconfiguration

Description: Combining origins="*" with supports_credentials=True on CORS(...) or @cross_origin(...) makes Flask-CORS reflect every request's Origin header back as Access-Control-Allow-Origin while also sending cookies and Authorization headers, which lets any site read authenticated responses. Replace the wildcard with an explicit list of trusted origins.

CWE: CWE-942 · OWASP: A07:2021, A07:2025

Severity Category

Flask Deprecated Apis

Rule ID: flask-deprecated-apis

Description: Call targets a Flask API removed or deprecated in modern releases (e.g. open_session, save_session, make_null_session, init_jinja_globals, request_globals_class, static_path, config.from_json, flask.json_available, flask.request.module, flask.testing.make_test_environ_builder). Replace it with the supported equivalent so the app keeps working on current Flask versions.

Severity Category

Flask Duplicate Handler Name

Rule ID: flask-duplicate-handler-name

Description: Two @app.route(...) decorators register a view named $R, but Flask requires unique endpoint names and will raise AssertionError: View function mapping is overwriting an existing endpoint function at startup. Rename one of the handlers or supply an explicit endpoint= argument on the decorator.

Severity Category

Flask URL For External True

Rule ID: flask-url-for-external-true

Description: Building absolute URLs via flask.url_for(..., _external=True) reuses the incoming Host header, so an attacker who controls that header can poison password-reset links, callback URLs, and similar artefacts. Either set _external=False, configure SERVER_NAME so the framework uses a known hostname, or validate the Host header upstream.

CWE: CWE-673 · OWASP: A03:2021, A05:2025

Severity Category

Flask Wtf CSRF Disabled

Rule ID: flask-wtf-csrf-disabled

Description: Assigning WTF_CSRF_ENABLED = False on the Flask config switches off Flask-WTF's CSRF protection for every form and JSON POST handled by the app, leaving state-changing endpoints exposed to cross-site requests. Remove the override (or restrict it to test-only configs) and keep CSRF tokens validated by default.

CWE: CWE-352 · OWASP: A01:2021, A01:2025

Severity Category

Hashids With Flask Secret

Rule ID: hashids-with-flask-secret

Description: Passing app.config['SECRET_KEY'] as the salt for hashids.Hashids(...) leaks Flask's session-signing secret: HashIDs uses a reversible encoding, so an attacker that gathers enough generated IDs can recover the salt and therefore the Flask secret. Use a dedicated random salt for HashIDs and keep SECRET_KEY exclusive to Flask session and CSRF signing.

CWE: CWE-327 · OWASP: A02:2021

Severity Category

Host Header Injection Python

Rule ID: host-header-injection-python

Description: Concatenating flask.request.host into an HTTP URL trusts an attacker- controlled header to build that URL. The resulting request can be steered at internal services (SSRF), used to bypass password-reset flows, or weaponized for cache poisoning. Validate the host against an allowlist or use a fixed SERVER_NAME from configuration before constructing URLs.

CWE: CWE-20

Severity Category

Insecure Deserialization

Rule ID: insecure-deserialization

Description: A Flask route is invoking pickle.load, cPickle.load, dill.load, shelve.open, or yaml.load on data that may come from the client. These deserializers execute embedded gadget chains, so an attacker can achieve remote code execution simply by submitting a crafted payload. Switch to a safe format such as JSON, or use yaml.safe_load/signed formats with strict schemas.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Make Response With Unknown Content

Rule ID: make-response-with-unknown-content

Description: Passing arbitrary content into flask.make_response(...) bypasses Jinja's autoescape, so any unescaped HTML can become a cross-site scripting sink. Build HTML via flask.render_template() against a .html template, return JSON through flask.jsonify(), or wrap a known-safe redirect/template result before handing it to make_response.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Nan Injection

Rule ID: nan-injection

Description: Casting a flask.request value through float(...), bool(...) or complex(...) lets a client submit the literal strings "nan" or "inf", which become Python NaN/infinity and break comparisons, sorts, and arithmetic in unpredictable ways. Reject nan/inf explicitly (e.g. math.isfinite) or parse via int(...) when a finite integer is what the handler actually needs.

CWE: CWE-704

Severity Category

Open Redirect

Rule ID: open-redirect

Description: A value from flask.request.* flows into flask.redirect(...), giving a client full control over the Location header. This open redirect can be abused for phishing and OAuth/SSO callback hijacking. Build the target with flask.url_for(endpoint, ...) or check that urlparse(target).netloc matches the current host before redirecting.

CWE: CWE-601 · OWASP: A01:2021, A01:2025

Severity Category

OS System Injection

Rule ID: os-system-injection

Description: Data from a Flask request.args/request.form/route argument is being concatenated into an os.system(...) call, which executes through /bin/sh and is fully susceptible to shell metacharacters. Replace it with subprocess.run(["cmd", arg1, ...], shell=False) so arguments are passed as a list, or strictly validate the inputs against an allowlist.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Path Traversal Open

Rule ID: path-traversal-open

Description: A Flask request value reaches open(...) as the file path, allowing ../ sequences or absolute paths to escape the intended directory (path traversal / arbitrary file read or write). Resolve the path with os.path.realpath() and verify it stays inside an allowed base directory, or use flask.send_from_directory(...) which performs this check for downloads.

CWE: CWE-22 · OWASP: A05:2017, A01:2021, A01:2025

Severity Category

Raw HTML Format

Rule ID: raw-html-format

Description: Hand-rolled HTML strings (built via +, %, .format(), or f-strings) contain unescaped data drawn from flask.request.*, which sidesteps Jinja's autoescape and creates a reflected XSS sink. Render through flask.render_template('page.html', ...), or sanitize the value with markupsafe.escape(...) before concatenating.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Render Template String

Rule ID: render-template-string

Description: Using flask.render_template_string(...) evaluates the supplied template text through Jinja2, so any user-controlled input concatenated into that string can break out into the template language and trigger server-side template injection (SSTI) leading to RCE. Render a static .html template via flask.render_template() and pass user data as context variables.

CWE: CWE-96 · OWASP: A03:2021, A05:2025

Severity Category

Response Contains Unsanitized Input

Rule ID: response-contains-unsanitized-input

Description: Values pulled from request.args.get(...) are forwarded into flask.make_response(...) without escaping, allowing attacker-controlled markup to be reflected back to the browser as part of the response body. Render the output through a Jinja2 template (for example via render_template) so Flask's autoescaping neutralises the payload before it reaches the client.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Rule ID: secure-set-cookie

Description: $RESP.set_cookie(...) on a Flask Response/make_response object omits the secure, httponly, and samesite arguments, so the cookie defaults to being sent over plaintext HTTP, readable from JavaScript, and attached on cross-site requests. Pass secure=True, httponly=True, samesite='Lax' explicitly, or set the equivalent SESSION_COOKIE_* keys in the Flask configuration.

CWE: CWE-614 · OWASP: A05:2021, A02:2025

Severity Category

SSRF Requests

Rule ID: ssrf-requests

Description: A value from flask.request is forwarded into requests.get/post/put/..., letting a client steer the outbound HTTP request at internal services (metadata endpoints, intranet hosts) for server-side request forgery. Parse the URL and confirm the scheme and host are on an allowlist before issuing the request, and never echo the response straight back to the caller.

CWE: CWE-918 · OWASP: A10:2021, A01:2025

Severity Category

Subprocess Injection

Rule ID: subprocess-injection

Description: Tainted data from flask.request.* reaches subprocess.$FUNC(...) either as the dynamic program path or inside a shell invocation (["sh", "-c", ...], ["python", ...]), which lets a client smuggle arbitrary commands. Pass a fixed argv list with shell=False, or map request data through a dictionary that whitelists the allowed commands.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Tainted SQL String

Rule ID: tainted-sql-string

Description: A SELECT/INSERT/UPDATE/DELETE statement is being stitched together via +, %, .format(), or an f-string using data from flask.request, which is the textbook recipe for SQL injection. Use parameterized queries (cursor.execute(sql, params) or SQLAlchemy text(...).bindparams(...)) so the driver, not the formatter, escapes the values.

CWE: CWE-704 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Tainted URL Host

Rule ID: tainted-url-host

Description: A flask.request value is interpolated into the host portion of a URL (after ://) via +, %, .format(), or an f-string. Anything that consumes the resulting URL (outbound HTTP, redirect, link in a response) can then be steered at attacker-controlled or internal hosts, enabling SSRF or credential leakage. Keep the host fixed or look it up from an allowlist keyed by safe identifiers.

CWE: CWE-918 · OWASP: A10:2021, A01:2025

Severity Category

Template Autoescape Off

Rule ID: template-autoescape-off

Description: An {% autoescape false %} block opens a section of the Flask template where Jinja2 emits raw HTML for every expression inside it. Any variable that reaches this region is no longer escaped, so attacker-controlled markup will execute in the rendered page. Either remove the block or scope it tightly to constants you fully control.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Template Unescaped With Safe

Rule ID: template-unescaped-with-safe

Description: Piping a template expression through the | safe filter marks the value as pre-escaped HTML and tells Jinja2 to emit it verbatim. When the value originates from request data, this becomes a stored or reflected XSS sink. Drop the filter so autoescape applies, or convert the value to a trusted constant before rendering.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Template Unquoted Attribute Var

Rule ID: template-unquoted-attribute-var

Description: An HTML attribute is assigned a {{ request.* }} value without surrounding quotes, so an attacker can break out of the attribute boundary and attach event handlers such as onmouseover=.... Always wrap dynamic attribute values in double quotes (="{{ var }}") so attribute-context escaping is effective.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Unescaped Template Extension

Rule ID: unescaped-template-extension

Description: flask.render_template(...) only turns on Jinja autoescape for templates whose names end in .html, .htm, .xml, or .xhtml. Rendering a file with any other extension (or an extension chosen at runtime) ships unescaped output to the browser and creates a cross-site scripting risk. Rename the template to use a recognised extension, or call select_autoescape explicitly on the Jinja environment.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Incorrect Autoescape Disabled

Rule ID: incorrect-autoescape-disabled

Description: jinja2.Environment(...) is constructed with an explicit autoescape value that is neither True nor jinja2.select_autoescape(...), which means HTML in rendered variables will be emitted verbatim. For any template that ends up in a browser this is an XSS sink. Pass autoescape=True, or use jinja2.select_autoescape(...) to opt in by extension.

CWE: CWE-116 · OWASP: A03:2021, A05:2025

Severity Category

Missing Autoescape Disabled

Rule ID: missing-autoescape-disabled

Description: No autoescape keyword is supplied to jinja2.Environment(...), so the constructor falls back to its insecure default of False and every variable is rendered as raw HTML. Add autoescape=True when instantiating the environment, or pass jinja2.select_autoescape(["html", "xml"]) to enable escaping for the file types that need it.

CWE: CWE-116 · OWASP: A03:2021, A05:2025

Severity Category

JWT Python Exposed Credentials

Rule ID: jwt-python-exposed-credentials

Description: A "password" key is being embedded in a payload handed to jwt.encode(...). JWT claims are merely signed and base64 encoded, so anyone with the token can read the plaintext credential. Remove the password from the claim set and reference the user by an opaque identifier instead.

CWE: CWE-522 · OWASP: A02:2017, A04:2021, A06:2025

Severity Category

JWT Python Exposed Data

Rule ID: jwt-python-exposed-data

Description: A function parameter flows directly into jwt.encode(...) as the payload, meaning whatever the caller passes in becomes part of a token that is only base64 encoded, not encrypted. Audit the payload construction and strip any PII, internal identifiers, or secret material before signing.

CWE: CWE-522 · OWASP: A02:2017, A04:2021, A06:2025

Severity Category

JWT Python Hardcoded Secret

Rule ID: jwt-python-hardcoded-secret

Description: The signing secret passed to jwt.encode(payload, "...", ...) is a string literal, so anyone with read access to the source repository can mint or tamper with tokens. Load the secret from a runtime configuration source (environment variables, a secret manager, etc.) so it can be rotated without code changes.

CWE: CWE-522 · OWASP: A02:2017, A04:2021, A06:2025

Severity Category

JWT Python None Alg

Rule ID: jwt-python-none-alg

Description: Either jwt.encode(..., algorithm="none", ...) or jwt.decode(..., algorithms=[..., "none", ...], ...) is in use here. The none algorithm produces an unsigned token, so any attacker can forge a payload that the verifier still treats as authentic. Restrict the accepted algorithms list to strong schemes such as HS256, RS256, or EdDSA.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Unverified JWT Decode

Rule ID: unverified-jwt-decode

Description: jwt.decode(...) is being invoked with options={"verify_signature": False}, so the library returns the embedded claims without checking the cryptographic signature. Any attacker who can submit a token to this endpoint can therefore impersonate any user. Drop the override (or set the flag to True) so signatures are always verified.

CWE: CWE-287 · OWASP: A02:2017, A07:2021, A07:2025

Severity Category

Aiopg Sqli

Rule ID: aiopg-sqli

Description: The query passed to aiopg cursor execute is built from string concatenation, .format, % formatting, or an f-string with non-literal values. Any tainted segment becomes a SQL injection vector. Use the driver's parameter binding instead, e.g. await cur.execute("SELECT %s FROM table", (user_value,)), so the value is escaped by the driver.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Asyncpg Sqli

Rule ID: asyncpg-sqli

Description: A dynamically assembled SQL string is being handed to an asyncpg.Connection method (fetch, execute, prepare, etc.). When the interpolated value comes from a request it can carry a SQL injection payload. Switch to asyncpg's positional placeholders -- await conn.fetch("SELECT $1 FROM table", value) -- or build a prepared statement via Connection.prepare.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Avoid Bind To All Interfaces

Rule ID: avoid-bind-to-all-interfaces

Description: The socket is being bound to 0.0.0.0, ::, or an empty host string, which causes the listener to accept connections on every network interface — including ones reachable from the public internet or untrusted VPCs. Bind to a specific loopback or private-network address (e.g. 127.0.0.1 for local-only services) and read the value from configuration rather than hardcoding it.

CWE: CWE-200 · OWASP: A01:2021, A01:2025

Severity Category

Avoid CPickle

Rule ID: avoid-cPickle

Description: cPickle is the legacy Python 2 alias for the C implementation of pickle and inherits the same attack surface: a tainted blob passed to cPickle.load or cPickle.loads executes opcodes that can call any importable Python callable. Migrate to json (or a binary format with a fixed schema such as Protocol Buffers) for any data crossing a trust boundary.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Avoid Dill

Rule ID: avoid-dill

Description: A dill.$FUNC call is being applied to non-literal data. dill extends pickle to handle closures and lambdas, but it preserves the same __reduce__-based execution model, so loading a hostile blob still grants arbitrary code execution. Prefer JSON, MessagePack with a registry, or another data-only format for transferring values between trust zones.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Avoid Jsonpickle

Rule ID: avoid-jsonpickle

Description: jsonpickle.decode is being invoked on non-literal data. The library reconstructs Python objects from the JSON envelope, including calling arbitrary class constructors, so an attacker who controls the payload can achieve remote code execution. Restrict deserialization to the standard library json module and rebuild domain objects manually from the parsed primitives.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Avoid Pickle

Rule ID: avoid-pickle

Description: A pickle.$FUNC (or _pickle.$FUNC) call is operating on non-literal data. The pickle wire format encodes REDUCE opcodes that invoke arbitrary callables during pickle.loads, which is the canonical Python remote code execution sink. Serialize with json.dumps or another schema-driven text format and validate the structure on load.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Avoid Pyyaml Load

Rule ID: avoid-pyyaml-load

Description: PyYAML is being invoked with an unsafe loader: yaml.unsafe_load, or yaml.load/yaml.load_all parameterised with yaml.Loader, yaml.UnsafeLoader, or yaml.CLoader. Those loaders honour the !!python/ tag family and instantiate arbitrary classes, which lets a crafted document execute Python at load time. Use yaml.safe_load (or Loader=yaml.SafeLoader) for any input that is not fully under your control.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Avoid Shelve

Rule ID: avoid-shelve

Description: The shelve module persists values by calling pickle under the hood, so reading a tampered shelf file is equivalent to running pickle.loads on attacker-controlled bytes and yields arbitrary code execution. Store structured data in a SQL-backed database or a JSON document keyed by an authenticated identifier instead.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Avoid Unsafe Ruamel

Rule ID: avoid-unsafe-ruamel

Description: Instantiating ruamel.yaml.YAML with typ='unsafe' or typ='base' activates a loader that can materialize arbitrary Python objects from !!python/... tags, turning a tainted document into a code-execution primitive. Configure the parser with typ='safe' (or typ='rt' for round-trip needs) so only standard YAML scalars and collections are produced.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

Baseclass Attribute Override

Rule ID: baseclass-attribute-override

Description: Class $C inherits from both $A and $B, and each base defines its own $F, so Python's MRO will resolve $F to exactly one of them and the other implementation is effectively hidden. Rename the conflicting method on one base, override $F explicitly in $C to delegate to both, or use composition instead of multiple inheritance to make the resolution intentional.

Severity Category

Cannot Cache Generators

Rule ID: cannot-cache-generators

Description: Decorating a generator function with @functools.lru_cache caches the generator object itself, not its values, so the second call returns the same already-exhausted iterator and iteration yields nothing. Either drop the cache, eagerly materialise the results into a list/tuple inside the cached function, or use functools.cache over a non-generator wrapper.

Severity Category

Dangerous Annotations Usage

Rule ID: dangerous-annotations-usage

Description: Writing arbitrary expressions into $C.__annotations__ is risky because typing.get_type_hints later evaluates those annotations as Python code against globals and locals, which turns an attacker-controlled annotation string into eval injection. Restrict annotations to literal types or whitelisted typing.* constructs and never assign untrusted values into __annotations__.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Asyncio Create Exec Audit

Rule ID: dangerous-asyncio-create-exec-audit

Description: A call to asyncio.create_subprocess_exec (or asyncio.subprocess.create_subprocess_exec) is being made with a non-literal program or argument vector. When any of those values are influenced by an attacker the spawned coroutine becomes a command-injection sink. Validate inputs against an allowlist and pass already-tokenized arguments, escaping any dynamic shell payload with shlex.quote.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Asyncio Create Exec Tainted Env Args

Rule ID: dangerous-asyncio-create-exec-tainted-env-args

Description: Taint flow reaches asyncio.create_subprocess_exec (or asyncio.subprocess.create_subprocess_exec) from CLI arguments or environment variables (sys.argv, os.environ, argparse, getopt, etc.), which lets the caller inject OS commands. Treat all such inputs as untrusted: validate against a fixed allowlist and quote dynamic fragments with shlex.quote before passing them as arguments.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Asyncio Exec Audit

Rule ID: dangerous-asyncio-exec-audit

Description: The event-loop API loop.subprocess_exec is being invoked with a dynamically built program path or argument list. Because the loop forwards each argument straight to the OS, any attacker-controlled component becomes an OS command-injection vector. Restrict the program path to a fixed value and sanitize argument fragments with shlex.quote before they reach the call.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Asyncio Exec Tainted Env Args

Rule ID: dangerous-asyncio-exec-tainted-env-args

Description: User-controlled data (CLI flags, os.environ, argparse/getopt output) flows directly into loop.subprocess_exec, producing an OS command-injection sink on the asyncio event loop. Constrain the program path to a hardcoded value and wrap any caller-supplied argument with shlex.quote, or refuse the value if it does not match a strict allowlist.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Asyncio Shell Audit

Rule ID: dangerous-asyncio-shell-audit

Description: Building the command string passed to asyncio.create_subprocess_shell (or loop.subprocess_shell) dynamically forwards the result to /bin/sh -c, so any concatenated input becomes a shell metacharacter primitive. Prefer the argv-form asyncio.create_subprocess_exec with a fixed program, or — if a shell is unavoidable — assemble the command from shlex.quote-escaped fragments only.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Asyncio Shell Tainted Env Args

Rule ID: dangerous-asyncio-shell-tainted-env-args

Description: Tainted CLI or environment input flows into asyncio.create_subprocess_shell/loop.subprocess_shell, which executes the resulting string through /bin/sh -c and exposes a full shell command-injection surface. Switch to the argv-based create_subprocess_exec API with a hardcoded program, or escape every untrusted fragment with shlex.quote before concatenating it into the command.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Globals Use

Rule ID: dangerous-globals-use

Description: A non-literal key is being used to index globals(), locals(), or func.__globals__. Treating that dictionary as a lookup table lets an attacker who controls the key resolve any module-level callable -- including eval, exec, or __import__ -- and execute arbitrary code. Replace the dynamic dispatch with an explicit allowlist mapping of names to functions.

CWE: CWE-96 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Interactive Code Run

Rule ID: dangerous-interactive-code-run

Description: Tainted request data flows into code.InteractiveConsole.push, InteractiveInterpreter.runsource, or runcode(code.compile_command(...)). Any of these helpers compile and execute the supplied string as Python, giving an attacker arbitrary code execution. Never feed untrusted input to the code module -- restrict it to operator-only REPL surfaces.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Interactive Code Run Audit

Rule ID: dangerous-interactive-code-run-audit

Description: Feeding a non-literal payload into code.InteractiveConsole.push, InteractiveInterpreter.runsource, or runcode(code.compile_command(...)) will compile and execute that string as Python in the current process, giving any attacker that controls the input full code-execution. Treat these REPL APIs as privileged: hardcode the payload or gate it behind a strict allowlist before invoking the call.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Interactive Code Run Tainted Env Args

Rule ID: dangerous-interactive-code-run-tainted-env-args

Description: User-supplied input (from sys.argv, os.environ, argparse, or getopt) reaches code.InteractiveConsole.push/InteractiveInterpreter.runsource/runcode, where it is compiled and executed as Python — a direct path to remote code execution. Remove the dynamic source or enforce a strict allowlist of fixed snippets before invoking these REPL entry points.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous OS Exec

Rule ID: dangerous-os-exec

Description: Tainted input is being passed into os.execl*/os.execv* -- either as the program path or as the argument vector to a shell wrapped via sh -c. Because these calls replace the current process with the supplied command, attacker-supplied content yields OS command injection. Hard-code the executable path and pass user data only as discrete, validated argv elements (never through -c).

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous OS Exec Audit

Rule ID: dangerous-os-exec-audit

Description: A os.exec* family call (os.execv, os.execve, os.execlp, etc.) is being invoked with a dynamic program path or -c shell payload. os.exec* replaces the current process image with whatever the arguments point to, so any non-literal value here is a high-impact command-injection sink. Restrict the program path to a constant and quote shell payloads with shlex.quote before they reach the call.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous OS Exec Tainted Env Args

Rule ID: dangerous-os-exec-tainted-env-args

Description: Tainted CLI/environment input flows into an os.exec* call (os.execv, os.execve, os.execlp, …), which replaces the current process with whatever the attacker specifies — a direct OS command-injection vector. Reject the input or constrain it via an allowlist, and pass shell payloads only after escaping them with shlex.quote.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Spawn Process

Rule ID: dangerous-spawn-process

Description: User-controlled data is flowing into os.spawn*, os.posix_spawn*, or os.startfile, including the -c payload of shell-prefixed invocations. These functions launch a child process with the provided command, so tainted arguments translate directly into OS command injection. Resolve the binary path statically and forward untrusted values only as separate, validated arguments.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Spawn Process Audit

Rule ID: dangerous-spawn-process-audit

Description: os.spawn*, os.posix_spawn, or os.startfile is being called with a non-literal program or -c payload. These APIs launch external processes with the supplied arguments verbatim, so any dynamic fragment can be turned into a command-injection primitive. Hardcode the program path and quote untrusted shell payloads with shlex.quote before spawning.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Spawn Process Tainted Env Args

Rule ID: dangerous-spawn-process-tainted-env-args

Description: Untrusted CLI/environment data is reaching os.spawn*/os.posix_spawn/os.startfile, all of which launch external processes with the arguments you supply. That gives a caller arbitrary command execution rights on the host. Validate input against an allowlist, hardcode the program path, and quote shell payloads with shlex.quote before spawning.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Subinterpreters Run String

Rule ID: dangerous-subinterpreters-run-string

Description: Tainted input reaches _xxsubinterpreters.run_string, which compiles and executes the supplied source inside a fresh subinterpreter. The subinterpreter still shares the host process's privileges, so attacker code runs with full application permissions. Never feed external strings into this CPython internal API.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Subinterpreters Run String Audit

Rule ID: dangerous-subinterpreters-run-string-audit

Description: Passing a non-literal source string to _xxsubinterpreters.run_string compiles and runs that text inside a subinterpreter — equivalent to exec() for code-injection purposes. If any caller-controlled value reaches this point the attacker can execute arbitrary Python. Limit the payload to a fixed string or to entries from a strict allowlist, and avoid building the source dynamically.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Subinterpreters Run String Tainted Env Args

Rule ID: dangerous-subinterpreters-run-string-tainted-env-args

Description: Tainted data from sys.argv, os.environ, argparse, or getopt is being fed into _xxsubinterpreters.run_string, which compiles and executes that source inside a subinterpreter. The result is full Python code-execution under attacker control. Refuse to forward such input and keep the payload constant or whitelisted.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Subprocess Use

Rule ID: dangerous-subprocess-use

Description: subprocess.$FUNC is being called with tainted data as either the program, the -c payload for a shell wrapper, or an argument to a python invocation. Each of these paths reaches execve with attacker-controlled bytes, which is a textbook command-injection sink. Pin the binary, drop the shell wrapper, and pass user values as discrete argv entries (escape with shlex.quote if a shell really is unavoidable).

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Subprocess Use Audit

Rule ID: dangerous-subprocess-use-audit

Description: subprocess.$FUNC (Popen, run, call, check_output, …) is being invoked with a non-literal program or -c payload. With dynamic values an attacker can choose what binary runs or smuggle metacharacters through bash -c/python -c. Pin the executable to a constant, prefer the argv-list form, and wrap any caller-supplied fragment with shlex.quote.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Subprocess Use Tainted Env Args

Rule ID: dangerous-subprocess-use-tainted-env-args

Description: Tainted CLI/environment input reaches subprocess.$FUNC, putting attacker data straight into the program path or shell/python -c payload. This is a textbook OS command-injection sink. Either refuse to forward the value, or scope it via an allowlist and wrap dynamic fragments with shlex.quote before passing them as arguments.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous System Call

Rule ID: dangerous-system-call

Description: Request-derived data flows into os.system or one of the os.popen* variants (including obfuscated lookups via getattr or __import__("os")). Both APIs hand the full command string to /bin/sh -c, so any tainted fragment introduces OS command injection. Switch to subprocess.run with a fixed program path and shell=False, passing arguments as a list.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous System Call Audit

Rule ID: dangerous-system-call-audit

Description: os.system (or one of the os.popen* variants) is being called with a non-literal command string. These helpers always spawn /bin/sh -c <cmd>, so concatenating any dynamic value into the argument is a direct shell-injection vector. Switch to subprocess.run with an argv list and a hardcoded executable, and escape any remaining dynamic fragments with shlex.quote.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous System Call Tainted Env Args

Rule ID: dangerous-system-call-tainted-env-args

Description: Tainted CLI/environment input reaches os.system/os.popen/os.popen[2-4], which always wrap the payload in /bin/sh -c. That turns user input into an arbitrary shell command. Replace these calls with subprocess.run([...], shell=False) against a hardcoded executable, and validate or shlex.quote any dynamic argument before passing it in.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Dangerous Testcapi Run In Subinterp

Rule ID: dangerous-testcapi-run-in-subinterp

Description: Tainted data is passed to _testcapi.run_in_subinterp or test.support.run_in_subinterp, both of which compile and execute the string as Python inside a fresh subinterpreter. The new interpreter still runs in the host process, so attacker-supplied code retains the application's privileges. These test-only helpers must never receive untrusted input.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Testcapi Run In Subinterp Audit

Rule ID: dangerous-testcapi-run-in-subinterp-audit

Description: A non-literal source string is being handed to _testcapi.run_in_subinterp (or test.support.run_in_subinterp). These helpers compile and execute the supplied text inside a fresh interpreter, which is functionally equivalent to exec() from an attacker's perspective. Keep the argument literal or restricted to a whitelist of fixed snippets to avoid Python eval injection.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Dangerous Testcapi Run In Subinterp Tainted Env Args

Rule ID: dangerous-testcapi-run-in-subinterp-tainted-env-args

Description: Taint flow shows CLI or environment data reaching _testcapi.run_in_subinterp/test.support.run_in_subinterp, where it is compiled and executed inside a sub-interpreter. That gives the caller arbitrary Python code-execution. Strip the dynamic source — accept only a fixed payload or one drawn from a strict allowlist before invoking these helpers.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Default Mutable Dict

Rule ID: default-mutable-dict

Description: Declaring $D={} as a default argument and then writing to it with $D[...] = ..., $D.update(...), or $D.setdefault(...) is the classic Python mutable-default pitfall: the dict is created once when $F is defined and every later call that omits $D mutates and observes the same shared object, so keys leak across unrelated callers. Use the sentinel pattern def $F(..., $D=None): if $D is None: $D = {} so each invocation starts with a fresh dictionary.

Severity Category

Default Mutable List

Rule ID: default-mutable-list

Description: The default value $D=[] on $F is evaluated a single time when the def statement runs, so calls that rely on the default all reach into the same list; once append, extend, or insert runs, every later caller sees the accumulated items from previous invocations. Default the parameter to None and create a new list inside the body ($D = [] if $D is None else $D) so each call starts with its own.

Severity Category

Dict Del While Iterate

Rule ID: dict-del-while-iterate

Description: Deleting $DICT[$KEY] while iterating over $DICT.items() or $DICT.keys() mutates the underlying mapping that the view object is walking, which raises RuntimeError: dictionary changed size during iteration on the very next step. Snapshot the keys first with for $KEY in list($DICT): ... or build the kept entries into a new dict via a comprehension instead of deleting in place.

Severity Category

Disabled Cert Validation

Rule ID: disabled-cert-validation

Description: The cert_reqs argument supplied to urllib3.PoolManager/HTTPSConnectionPool/ssl.wrap_socket is set to CERT_NONE or CERT_OPTIONAL, which turns off TLS server-certificate verification and makes the connection vulnerable to anyone able to MITM the path. Use ssl.CERT_REQUIRED (the default) together with a trusted CA bundle so the peer is authenticated on every handshake.

CWE: CWE-295 · OWASP: A03:2017, A07:2021, A07:2025

Severity Category

Dynamic Urllib Use Detected

Rule ID: dynamic-urllib-use-detected

Description: A dynamic URL is being passed to urllib.urlopen/urllib.request.urlopen/urlretrieve (or a URLopener.open/retrieve). Because these helpers honour file://, ftp://, and other handlers, a tainted URL can be coerced into local file disclosure or SSRF. Switch to requests with an explicit scheme allowlist, or validate the URL's scheme/host before fetching.

CWE: CWE-939 · OWASP: A01:2017

Severity Category

Eval Detected

Rule ID: eval-detected

Description: Calling eval() on a non-literal expression compiles and runs the string as Python in the current scope, so any caller-controlled fragment becomes a remote-code-execution primitive. Replace eval with a parser tuned to the input — ast.literal_eval for safe Python literals, json.loads for JSON, or a hand-written grammar for structured DSLs — and never let untrusted data reach eval.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Exec Detected

Rule ID: exec-detected

Description: exec() is being called on a non-literal argument, which compiles and runs the supplied string as Python in the enclosing namespace. Any tainted byte that reaches this call is a remote-code-execution primitive. Refactor the logic so behavior is selected through ordinary control flow (a dict dispatch or getattr against an allowlist), and keep untrusted input far away from exec.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

File Object Redefined Before Close

Rule ID: file-object-redefined-before-close

Description: Reassigning $F from a second open(...) without calling $F.close() on the previous handle abandons that file descriptor; it stays open until the garbage collector eventually finalises the object, which on Windows blocks deletion and on long-running processes can exhaust the descriptor table. Close the first handle before reopening, or wrap each open in a with statement so it is released deterministically.

Severity Category

Formatted SQL Query

Rule ID: formatted-sql-query

Description: The SQL string passed to $DB.execute is built with % formatting, str.format, or an f-string, which concatenates raw values into the query text and exposes the call to SQL injection. Pass the SQL as a parameterized statement (cursor.execute("... WHERE x = ?", (value,))) so the driver, not Python's string formatter, handles quoting and types.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Hardcoded Password Default Argument

Rule ID: hardcoded-password-default-argument

Description: The password= parameter of $FUNC carries a hardcoded default string. Any caller that omits the argument will silently authenticate with that baked-in value, exposing the credential in source code and turning every code-search hit into a leak. Drop the default (require the caller to pass a value), or read the credential from an environment variable or a secrets manager at call time.

CWE: CWE-798 · OWASP: A07:2021, A07:2025

Severity Category

HTTP Not HTTPS Connection

Rule ID: http-not-https-connection

Description: urllib3.HTTPConnectionPool (or urllib3.connectionpool.HTTPConnectionPool) creates a pool that speaks plain HTTP, so every request reuses an unencrypted TCP connection and exposes traffic to interception on the wire. Swap the class for urllib3.HTTPSConnectionPool and configure it with a CA bundle so connections are encrypted and the server certificate is verified.

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Httpsconnection Detected

Rule ID: httpsconnection-detected

Description: Constructing a http.client.HTTPSConnection (or its httplib/six.moves aliases) without an explicit context=ssl.create_default_context() relies on the interpreter's historical default — and on CPython before 3.4.3 that default did not verify the server certificate at all. Always pass a ssl.create_default_context() (or equivalent) so hostname and chain validation are enforced.

CWE: CWE-295 · OWASP: A03:2017, A07:2021, A07:2025

Severity Category

Identical Is Comparison

Rule ID: identical-is-comparison

Description: Comparing a value to itself with $S is $S always evaluates to True (except for the NaN corner case via ==) and is almost certainly a typo. Replace one side with the operand you actually meant to test against, or drop the redundant check entirely.

Severity Category

Insecure File Permissions

Rule ID: insecure-file-permissions

Description: The mode $BITS being passed to os.chmod/os.lchmod/os.fchmod grants group or world write/execute rights (or sets the S_IWGRP/S_IWOTH/S_IRWXG/S_IRWXO bits), which leaves the file readable or modifiable by users beyond the owner. Tighten the mode to something like 0o600 or 0o644 so only the owning user can modify the file.

CWE: CWE-276 · OWASP: A01:2021, A01:2025

Severity Category

Insecure Hash Algorithm MD5

Rule ID: insecure-hash-algorithm-md5

Description: hashlib.md5 is being invoked without usedforsecurity=False. MD5 is practically broken against collision attacks, so any signature, integrity tag, or password derivation built on it can be forged. Replace the call with hashlib.sha256 (or hashlib.sha3_256); if the hash is only used as a non-security checksum, set usedforsecurity=False to make the intent explicit.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Hash Algorithm SHA1

Rule ID: insecure-hash-algorithm-sha1

Description: SHA-1 has demonstrated chosen-prefix collisions (SHAttered, Shambles), so hashlib.sha1 is no longer safe for digital signatures, certificate fingerprints, or other security-sensitive uses. Replace it with hashlib.sha256 or a SHA-3 variant; legitimate non-security checksums should switch to hashlib.sha256(..., usedforsecurity=False).

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Hash Function

Rule ID: insecure-hash-function

Description: hashlib.new is being constructed with the algorithm name md4 or md5, both of which fail modern collision-resistance requirements and have public exploit chains (Flame malware, chosen-prefix attacks). Pass "sha256" (or a SHA-3 family identifier) to hashlib.new, or call the dedicated constructor directly such as hashlib.sha256().

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Urlopen

Rule ID: insecure-urlopen

Description: urllib.request.urlopen is being pointed at an http:// URL, so the HTTP exchange — headers, cookies, and body — leaves the process unencrypted and unauthenticated. Switch the scheme to https:// so TLS protects the request, and verify the response certificate via ssl.create_default_context().

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Urlopen FTP

Rule ID: insecure-urlopen-ftp

Description: urllib.request.urlopen is being asked to fetch an ftp:// URL, which sends credentials and file contents over the wire in cleartext. Because urllib cannot speak SFTP, swap this call for a real SFTP library such as paramiko.SFTPClient or pysftp, or front the transfer with FTPS via ftplib.FTP_TLS.

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Uuid Version

Rule ID: insecure-uuid-version

Description: uuid.uuid1() derives identifiers from the host's MAC address and a timestamp, so its output is predictable and leaks hardware information. Attackers can guess neighbouring IDs (the "sandwich attack") whenever these values are exposed. Use uuid.uuid4() -- which is backed by os.urandom -- for any user-visible or security-relevant identifier.

CWE: CWE-330 · OWASP: A02:2021, A04:2025

Severity Category

Is Not Is Not

Rule ID: is-not-is-not

Description: Writing $S is (not ...) parses as the identity operator is applied to the boolean produced by not ..., so Python is actually asking whether $S is the very object True or False rather than performing the intended "is not" identity check. Drop the parentheses and use the compound operator $S is not ... so the comparison reads correctly.

Severity Category

List Modify While Iterate

Rule ID: list-modify-while-iterate

Description: Mutating $LIST with append, extend, insert, pop, or remove from inside for ... in $LIST shifts the indices that the iterator is walking, which causes elements to be skipped, visited twice, or — in the case of append/extend — produces an infinite loop. Iterate over a defensive copy (for $ELEMENT in list($LIST):) or collect the changes and apply them after the loop finishes.

Severity Category

Listen Eval

Rule ID: listen-eval

Description: logging.config.listen() accepts logging configs over a local socket and runs filter/() callable fields through eval, so any process able to write to that loopback port can execute Python in this interpreter. Pass a verify= callback that validates configurations against an HMAC or signature before they are applied — or do not expose the listener at all in production.

CWE: CWE-95 · OWASP: A03:2021, A05:2025

Severity Category

Mako Templates Detected

Rule ID: mako-templates-detected

Description: Instantiating mako.template.Template(...) produces a renderer that emits expression values verbatim, because Mako has no global autoescape — every interpolated variable must carry an explicit | h (HTML) or | u (URL) filter to be safe. Wrap each ${...} site with the appropriate filter, or move to a template engine such as Jinja2 with autoescape=True enabled by default.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Marshal Usage

Rule ID: marshal-usage

Description: marshal.dump/dumps/load/loads is being used outside CPython's internal .pyc use case; the format is documented as unsafe against malformed input and can crash the interpreter or be abused to load attacker-controlled code objects. Persist application data with json, tomllib, or a schema-driven binary format (Protocol Buffers, Avro) instead.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

MD5 Used As Password

Rule ID: md5-used-as-password

Description: An MD5 digest (hashlib.md5, hashlib.new("MD5", …), Crypto.Hash.MD5, or cryptography.hazmat.primitives.hashes.MD5) is feeding a parameter that looks like a password, yet MD5 is fast and unsalted — attackers can brute-force billions of guesses per second on commodity GPUs. Hash passwords with a deliberately slow KDF such as hashlib.scrypt, argon2-cffi, or bcrypt, using a per-user random salt.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Multiprocessing Recv

Rule ID: multiprocessing-recv

Description: Reading from a multiprocessing.connection.Connection or Client invokes pickle under the hood, so any peer that can write to this connection can trigger arbitrary code execution via crafted bytes. Authenticate the channel (for example with Connection.send_bytes plus an HMAC, or multiprocessing.connection.Client(authkey=...)) before calling recv(), or restrict the endpoint to a trusted Pipe() peer.

CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025

Severity Category

No Set Ciphers

Rule ID: no-set-ciphers

Description: Calling $CONTEXT.set_ciphers(...) overrides the curated cipher list that ssl.create_default_context() ships with and can silently re-enable weak suites such as RC4, 3DES, or anonymous DH. Unless you are enforcing a stricter modern profile, drop the call and rely on the default suite, or audit the cipher string carefully against an established standard like Mozilla's Modern profile.

CWE: CWE-326 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Non Literal Import

Rule ID: non-literal-import

Description: importlib.import_module is being called with a non-literal module name, so anyone who can influence $NAME can pick which Python module is loaded and executed in this process — including attacker-supplied entries on sys.path. Resolve the requested feature through a hardcoded dispatch table or an explicit allowlist of acceptable module names before calling import_module.

CWE: CWE-706 · OWASP: A01:2021, A01:2025

Severity Category

Paramiko Exec Command

Rule ID: paramiko-exec-command

Description: A non-literal command is being passed to paramiko.SSHClient.exec_command, which runs the string on the remote server through a shell. If any portion of the argument originates from user input it enables remote command injection. Build the command from a hardcoded template and pass untrusted values as separate, validated parameters.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Paramiko Implicit Trust Host Key

Rule ID: paramiko-implicit-trust-host-key

Description: Calling set_missing_host_key_policy with paramiko.client.AutoAddPolicy or WarningPolicy causes the SSH client to silently accept any server host key, leaving the connection vulnerable to man-in-the-middle attacks. Pre-populate known_hosts and switch to paramiko.client.RejectPolicy or a custom subclass that performs real host key validation.

CWE: CWE-322 · OWASP: A02:2021, A04:2025

Severity Category

Pg8000 Sqli

Rule ID: pg8000-sqli

Description: SQL constructed via concatenation, % formatting, .format, or an f-string is reaching a pg8000 cursor (run, execute, executemany, or prepare). User-controlled fragments inside that string permit SQL injection. Rely on named parameters -- conn.run("SELECT :value FROM table", value=myvalue) -- or precompile statements with conn.prepare("SELECT (:v) FROM table").

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Psycopg Sqli

Rule ID: psycopg-sqli

Description: A psycopg2 cursor call (execute, executemany, mogrify) receives a dynamically built query string with non-literal interpolation, which exposes the application to SQL injection when those values come from user input. Use psycopg2.sql.SQL to compose identifiers safely and pass values via the pyformat binding style, e.g. cur.execute("SELECT * FROM table WHERE name = %s", (user_input,)).

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Pytest Assert Match After Path Patch

Rule ID: pytest-assert_match-after-path-patch

Description: snapshot.assert_match from pytest-snapshot uses pathlib.Path internally to read and write snapshot files, so patching pathlib.Path (or one of its methods) earlier in the test redirects the snapshot's own filesystem calls and causes the assertion to load or write the wrong data. Restrict the patch to the production code under test (for example with mocker.patch.object on the importing module) so assert_match keeps a real Path.

Severity Category

Python Logger Credential Disclosure

Rule ID: python-logger-credential-disclosure

Description: The format string $FORMAT_STRING passed to a logger.debug/info/warning/error/... call references a credential keyword (api_key, secret, token, password, ...) alongside a %s placeholder, which will write the secret straight into the log stream. Logs are routinely shipped to third-party pipelines, so redact the value (***, secrets.compare_digest, structured masking) before logging or skip the field entirely.

CWE: CWE-532 · OWASP: A09:2021, A09:2025

Severity Category

Python Reverse Shell

Rule ID: python-reverse-shell

Description: Reverse-shell pattern detected: a socket.socket is connected to $IP:$PORT and then $BINPATH is launched via pty.spawn or subprocess.call, which is the classic payload an attacker uses to gain interactive shell access. Remove this code from production paths; if it belongs to a test or red-team script, isolate it from any deployable artifact.

CWE: CWE-553

Severity Category

Raise Not Base Exception

Rule ID: raise-not-base-exception

Description: raise in Python 3 only accepts a class (or instance) that derives from BaseException; raising a bare string, a number, or anything else immediately produces TypeError: exceptions must derive from BaseException and your real error never surfaces. Wrap the payload in a proper exception, e.g. raise ValueError("..."), so the runtime can propagate it correctly.

Severity Category

Regex Dos

Rule ID: regex_dos

Description: The pattern compiled via re.compile exhibits catastrophic backtracking behavior. When matched against attacker-crafted input, the regex engine can take exponential time and stall the process, causing a regular expression denial of service (ReDoS). Refactor the pattern to avoid nested quantifiers on overlapping character classes, or evaluate it with a linear-time engine such as google-re2.

CWE: CWE-1333 · OWASP: A06:2017

Severity Category

Request Session HTTP In With Context

Rule ID: request-session-http-in-with-context

Description: A URL beginning with http:// is being passed through a with requests.Session(...) as $SESSION block, so the request leaves the application in cleartext and any network attacker can read or tamper with credentials and payload. Change the scheme to https:// (and pin a trusted CA bundle via Session.verify) so the connection is authenticated and encrypted.

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Request Session With HTTP

Rule ID: request-session-with-http

Description: An ad-hoc requests.Session(...).$W(...)/request(...) call is hitting an http:// URL, which means credentials, cookies, and response bodies all travel as plaintext. Migrate the URL to https:// and rely on Session.verify=True so TLS authenticates the host and encrypts the body in transit.

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Request With HTTP

Rule ID: request-with-http

Description: requests.get/requests.post/requests.request is being called with a plaintext http:// URL. Any header, body, or auth token sent through this call crosses the network in clear and is trivially sniffable on shared infrastructure. Update the URL to https:// (keep verify=True) so the request enjoys TLS confidentiality and server authentication.

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Return In Init

Rule ID: return-in-init

Description: Returning a non-None value from __init__ raises TypeError: __init__() should return None at construction time because Python reserves the return value of the initializer for itself. If you wanted to short-circuit the setup, use a bare return (or return None); if you wanted to expose a computed value, move it to a classmethod factory or set it on self.

Severity Category

Sha224 Hash

Rule ID: sha224-hash

Description: The 224-bit digest produced by hashlib.sha224 or hashlib.sha3_224 falls below the output length required by current NIST and many regulatory cryptography guidelines. Switch to hashlib.sha384, hashlib.sha512, or hashlib.sha3_384 so the hash retains sufficient strength for signatures and integrity checks.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

SSL Wrap Socket Is Deprecated

Rule ID: ssl-wrap-socket-is-deprecated

Description: The legacy ssl.wrap_socket() helper is deprecated and produces a TLS socket without SNI or hostname verification, which weakens transport security. Construct an ssl.SSLContext via ssl.create_default_context() and call context.wrap_socket(...) so certificate validation and modern defaults are applied.

CWE: CWE-326 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

String Concat In List

Rule ID: string-concat-in-list

Description: Two adjacent string literals inside a list or set (e.g. ["foo" "bar"]) are silently merged by Python's implicit string concatenation, producing one element instead of two and quietly losing the comma you almost certainly forgot. Add the missing comma between the literals, or merge them with explicit + if a single combined element was intended.

Severity Category

String Is Comparison

Rule ID: string-is-comparison

Description: Using is against a string literal tests whether the two operands are the exact same object in memory, not whether their characters are equal. Small strings happen to be interned by CPython so this can appear to work in trivial cases, but it breaks on longer strings, different interpreters, and dynamically built values. Compare strings with == (or !=) so Python checks the contents.

Severity Category

Subprocess List Passed As String

Rule ID: subprocess-list-passed-as-string

Description: A list of arguments is being collapsed via " ".join(...) before being handed to subprocess.run, subprocess.Popen, subprocess.call, check_call, or check_output. Re-joining loses the boundary between arguments and reintroduces shell-style parsing risks for any token that contains whitespace or metacharacters. Pass the original list directly so each element remains a discrete argv entry.

CWE: CWE-78 · OWASP: A03:2021, A05:2025

Severity Category

Subprocess Shell True

Rule ID: subprocess-shell-true

Description: subprocess.$FUNC is invoked with shell=True, which routes the command through /bin/sh and inherits the current environment, expanding glob, pipe, and substitution metacharacters. If any portion of the command derives from external data, the shell becomes a command-injection sink. Set shell=False and pass the program with its arguments as a list.

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

System Wildcard Detected

Rule ID: system-wildcard-detected

Description: A tar, chmod, chown, or rsync invocation containing a * wildcard is being launched through os.system, os.popen*, or subprocess with shell=True. The shell expands the wildcard before the command runs, so a crafted filename such as -e sh script.sh can smuggle extra flags and achieve arbitrary command execution. List the target paths explicitly or terminate options with -- after disabling shell interpretation.

CWE: CWE-155 · OWASP: A01:2017

Severity Category

Telnetlib

Rule ID: telnetlib

Description: Any call into telnetlib opens a cleartext Telnet session, transmitting credentials and command output without encryption or authenticity guarantees. Replace the connection with an SSH client (for example paramiko.SSHClient with proper host key verification) or another TLS-protected transport.

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Tempfile Insecure

Rule ID: tempfile-insecure

Description: tempfile.mktemp only reserves a candidate path and returns before any file is actually created, so an attacker (or a racing thread) can create that path first and have your subsequent open write into a file they control — a classic TOCTOU bug that the standard library explicitly deprecates. Switch to tempfile.NamedTemporaryFile, mkstemp, or TemporaryDirectory, which atomically create the file with safe permissions.

Severity Category

Tempfile Without Flush

Rule ID: tempfile-without-flush

Description: Reading $F.name from a tempfile.NamedTemporaryFile without first calling $F.flush() or $F.close() hands the path to another consumer while the data is still sitting in Python's write buffer, so the file on disk is empty or missing the latest writes. Flush (or close, when delete=False) the temp file before passing $F.name to a subprocess or library that opens it independently.

Severity Category

Test Is Missing Assert

Rule ID: test-is-missing-assert

Description: A bare $A == $B expression at statement level inside a test file computes a boolean and immediately discards it, so the test never actually fails when the equality does not hold. Prefix the comparison with assert (or the equivalent pytest/unittest helper) so the result is checked.

Severity Category

Uncaught Executor Exceptions

Rule ID: uncaught-executor-exceptions

Description: ThreadPoolExecutor.map(...) returns a lazy iterator and only re-raises a worker exception when its result is consumed, so discarding the return value swallows every failure raised inside the pool. Iterate over the result (for _ in $EXECUTOR.map(...): pass) or switch to submit plus Future.result() so worker exceptions actually surface.

Severity Category

Unverified SSL Context

Rule ID: unverified-ssl-context

Description: The code calls ssl._create_unverified_context() (directly or by reassigning ssl._create_default_https_context), which produces a context that skips certificate chain and hostname verification. TLS without these checks is trivially defeated by a man-in-the-middle. Use ssl.create_default_context() so the system trust store and hostname matching are enforced.

CWE: CWE-295 · OWASP: A03:2017, A07:2021, A07:2025

Severity Category

Use Defused XML

Rule ID: use-defused-xml

Description: Importing the stdlib xml package signals that XML parsing is happening through a parser that, by default, processes external entities and DTDs -- a well-known XXE and denial-of-service vector. Replace the import with the defusedxml package, whose drop-in replacements (defusedxml.ElementTree, defusedxml.sax, etc.) disable those features for untrusted input.

CWE: CWE-611 · OWASP: A04:2017, A05:2021, A02:2025

Severity Category

Use Defused XML Parse

Rule ID: use-defused-xml-parse

Description: Parsing a non-literal input with xml.etree.ElementTree.parse exposes the application to XML External Entity (XXE) and billion-laughs style denial of service, because the stdlib parser still resolves DTD entities by default. Swap the call for defusedxml.etree.ElementTree.parse, which disables entity expansion and external references.

CWE: CWE-611 · OWASP: A04:2017, A05:2021, A02:2025

Severity Category

Use Defused Xmlrpc

Rule ID: use-defused-xmlrpc

Description: Bringing in xmlrpc, xmlrpclib, or SimpleXMLRPCServer activates a transport whose default parser is susceptible to entity-expansion bombs and external-entity disclosure. Install defusedxml and call defusedxml.xmlrpc.monkey_patch() (or use the defusedxml.xmlrpc submodules directly) so XML-RPC traffic is parsed with hardened defaults.

CWE: CWE-776 · OWASP: A04:2017, A05:2021, A02:2025

Severity Category

Use Defusedcsv

Rule ID: use-defusedcsv

Description: csv.writer is being used to emit a CSV that may contain user-supplied cells. Spreadsheet clients interpret leading =, +, -, @, or tab characters as formulas, so a tainted value can trigger CSV injection -- data exfiltration or even local code execution -- once the recipient opens the file. Replace csv.writer with defusedcsv.writer, which keeps the same API while neutralising formula triggers.

CWE: CWE-1236 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Use FTP TLS

Rule ID: use-ftp-tls

Description: Instantiating ftplib.FTP opens a plaintext FTP control channel, so credentials and file contents cross the network unencrypted and any on-path attacker can read or tamper with them. Use ftplib.FTP_TLS with context=ssl.create_default_context() and call prot_p() so both the command and data channels are encrypted.

CWE: CWE-319 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Weak SSL Version

Rule ID: weak-ssl-version

Description: A protocol constant referencing SSLv2/v3 or TLS 1.0/1.1 (such as ssl.PROTOCOL_TLSv1 or pyOpenSSL.SSL.SSLv3_METHOD) is being used to configure TLS. These protocols are deprecated and harbor known cryptographic weaknesses. Negotiate ssl.PROTOCOL_TLS_CLIENT/PROTOCOL_TLS_SERVER with a minimum version of ssl.TLSVersion.TLSv1_2 (preferably 1.3).

CWE: CWE-326 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Writing To File In Read Mode

Rule ID: writing-to-file-in-read-mode

Description: Calling $FD.write(...) on a handle opened with mode "r" or "rb" raises io.UnsupportedOperation: not writable at runtime because the file was opened read-only. Open the file with a writable mode such as "w", "a", "r+", or their binary variants when you need to write to it.

Severity Category

Yield In Init

Rule ID: yield-in-init

Description: Including a yield anywhere in __init__ turns the initializer into a generator function, so calling MyClass(...) no longer constructs the object — it returns an unstarted generator and the instance is never initialized, which usually shows up later as TypeError: __init__() should return None. Move the lazy stream into a separate generator method on the class and keep __init__ purely for attribute setup.

Severity Category

Crypto Mode Without Authentication

Rule ID: crypto-mode-without-authentication

Description: AES.new(...) is configured with AES.MODE_CBC, AES.MODE_CTR, AES.MODE_CFB, or AES.MODE_OFB from PyCryptodome without an accompanying HMAC.new over the ciphertext, leaving the data without any integrity guarantee. An attacker who can tamper with ciphertext can run padding-oracle or bit-flipping attacks. Switch to AES.MODE_GCM (or another AEAD mode) so encryption and authentication are combined.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Cipher Algorithm Blowfish

Rule ID: insecure-cipher-algorithm-blowfish

Description: Crypto.Cipher.Blowfish.new(...) (or its Cryptodome mirror) instantiates a 64-bit block cipher that is vulnerable to birthday attacks like Sweet32 after only a few gigabytes of ciphertext. Replace it with a modern AEAD construction such as AES-GCM (AES.new(key, AES.MODE_GCM)) or a ChaCha20/Salsa20 stream cipher.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Cipher Algorithm DES

Rule ID: insecure-cipher-algorithm-des

Description: Use of Crypto.Cipher.DES.new(...) or Crypto.Cipher.DES3.new(...) (and their Cryptodome equivalents) is flagged here. DES has a 56-bit effective key and is brute-forceable in hours, while NIST has deprecated 3DES because of its 64-bit block size. Migrate to AES.new(key, AES.MODE_GCM) for authenticated encryption.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Cipher Algorithm Rc2

Rule ID: insecure-cipher-algorithm-rc2

Description: Crypto.Cipher.ARC2.new(...) (RC2) or its Cryptodome counterpart appears here. RC2 has known related-key and differential cryptanalysis weaknesses and a 64-bit block size that makes it unsuitable for any modern use case. Replace it with AES-GCM via AES.new(key, AES.MODE_GCM) or with ChaCha20-Poly1305.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Cipher Algorithm Rc4

Rule ID: insecure-cipher-algorithm-rc4

Description: RC4 is instantiated here through Crypto.Cipher.ARC4.new(...) (or the Cryptodome namespace). The keystream produced by RC4 leaks statistical biases that have been weaponised against TLS and WPA, and IETF RFC 7465 prohibits its use entirely. Switch to ChaCha20-Poly1305 (ChaCha20_Poly1305.new) or AES-GCM.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Cipher Algorithm Xor

Rule ID: insecure-cipher-algorithm-xor

Description: Plain XOR encryption is constructed via Crypto.Cipher.XOR.new(...) or its Cryptodome mirror. A repeating-key XOR offers no cryptographic strength and is trivially broken with known-plaintext analysis. Use an authenticated symmetric cipher such as AES.new(key, AES.MODE_GCM) instead.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Hash Algorithm Md2

Rule ID: insecure-hash-algorithm-md2

Description: Crypto.Hash.MD2.new(...) (or the Cryptodome.Hash.MD2.new variant) is being invoked. MD2 is a 128-bit digest from 1989 that has known preimage and collision attacks and is considered cryptographically broken. Use SHA256.new(), SHA3_256.new(), or BLAKE2b.new() from the same package instead.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Hash Algorithm Md4

Rule ID: insecure-hash-algorithm-md4

Description: Hashing via Crypto.Hash.MD4.new(...) (or its Cryptodome.Hash.MD4.new mirror) is cryptographically unsafe: full collisions can be produced in fractions of a second on commodity hardware. Replace the call with a SHA-2, SHA-3, or BLAKE2 digest such as SHA256.new().

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Hash Algorithm MD5

Rule ID: insecure-hash-algorithm-md5

Description: MD5 is being produced via Crypto.Hash.MD5.new(...) (or Cryptodome.Hash.MD5.new). MD5 has practical chosen-prefix collision attacks and is unsuitable for signatures, certificate fingerprints, or password hashing. For integrity digests choose SHA256.new() or BLAKE2b.new(); for password storage use a KDF such as Crypto.Protocol.KDF.scrypt or Argon2.

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insecure Hash Algorithm SHA1

Rule ID: insecure-hash-algorithm-sha1

Description: SHA-1 is produced here through Crypto.Hash.SHA.new(...) (or its Cryptodome.Hash.SHA.new counterpart). Since the 2017 SHAttered attack, SHA-1 collisions are demonstrably practical, making it unsafe for digital signatures or certificate hashing. Replace the call with SHA256.new() or SHA3_256.new().

CWE: CWE-327 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insufficient Dsa Key Size

Rule ID: insufficient-dsa-key-size

Description: Crypto.PublicKey.DSA.generate(...) (or its Cryptodome counterpart) is being called with bits below 2048, which leaves the resulting DSA key below the NIST SP 800-57 minimum strength. Pass bits=2048 or larger so the generated modulus matches contemporary security guidance.

CWE: CWE-326 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Insufficient Rsa Key Size

Rule ID: insufficient-rsa-key-size

Description: An RSA modulus smaller than 3072 bits is being generated through Crypto.PublicKey.RSA.generate(...) (or its Cryptodome mirror). For keys with a lifetime beyond 2030 NIST recommends at least 3072 bits to maintain a 128-bit security level. Increase the bits argument so the generated key remains resistant to factoring attacks.

CWE: CWE-326 · OWASP: A03:2017, A02:2021, A04:2025

Severity Category

Mongo Client Bad Auth

Rule ID: mongo-client-bad-auth

Description: pymongo.MongoClient(..., authMechanism='MONGODB-CR') requests the legacy challenge-response handshake which was deprecated in MongoDB 3.6 and removed in MongoDB 4.0. The server will reject the handshake (or fall back to weaker behaviour on older deployments). Use the SCRAM-based mechanism authMechanism='SCRAM-SHA-256'.

CWE: CWE-477

Severity Category

Rule ID: pyramid-authtkt-cookie-httponly-unsafe-default

Description: AuthTktCookieHelper / AuthTktAuthenticationPolicy is instantiated without an explicit httponly argument, so the Pyramid auth-ticket cookie is issued with the framework default that leaves the value reachable from JavaScript. A successful XSS on any page can then exfiltrate the session ticket. Pass httponly=True when constructing the helper or policy.

CWE: CWE-1004 · OWASP: A05:2021, A02:2025

Severity Category

Rule ID: pyramid-authtkt-cookie-httponly-unsafe-value

Description: The Pyramid AuthTktCookieHelper (or AuthTktAuthenticationPolicy) is built with httponly=False explicitly, which exposes the auth-ticket cookie to document.cookie reads in the browser. Any XSS on the application becomes an instant account takeover. Flip the argument to httponly=True.

CWE: CWE-1004 · OWASP: A05:2021, A02:2025

Severity Category

Rule ID: pyramid-authtkt-cookie-samesite

Description: The samesite argument supplied to AuthTktCookieHelper / AuthTktAuthenticationPolicy is something other than 'Lax', leaving the auth-ticket cookie attached to cross-site requests and reachable in CSRF or cross-origin navigation attacks. Set samesite='Lax' (or 'Strict' when the UX allows it) so the browser refuses to attach the ticket to third-party requests.

CWE: CWE-1275 · OWASP: A01:2021, A01:2025

Severity Category

Rule ID: pyramid-authtkt-cookie-secure-unsafe-default

Description: No secure keyword is provided to AuthTktCookieHelper / AuthTktAuthenticationPolicy, so Pyramid emits the auth-ticket cookie over plain HTTP as well as HTTPS. A network attacker on the same Wi-Fi or any intermediary can capture the session ticket in transit. Construct the helper or policy with secure=True.

CWE: CWE-614 · OWASP: A05:2021, A02:2025

Severity Category

Rule ID: pyramid-authtkt-cookie-secure-unsafe-value

Description: AuthTktCookieHelper / AuthTktAuthenticationPolicy is configured with secure=False, which forces the auth-ticket cookie to also travel over unencrypted HTTP and lets a passive eavesdropper steal the session. Change the argument to secure=True so the browser only ships the ticket on TLS connections.

CWE: CWE-614 · OWASP: A05:2021, A02:2025

Severity Category

Pyramid CSRF Check Disabled

Rule ID: pyramid-csrf-check-disabled

Description: This @view_config(...) decorator passes require_csrf=False, disabling Pyramid's per-view CSRF token validation for state-changing requests handled by the view. Attackers who can lure an authenticated user to a malicious page may trigger the action on the user's behalf. Remove the override or set require_csrf=True.

CWE: CWE-352 · OWASP: A01:2021, A01:2025

Severity Category

Pyramid CSRF Check Disabled Globally

Rule ID: pyramid-csrf-check-disabled-globally

Description: Configurator.set_default_csrf_options(require_csrf=False) switches off the automatic CSRF-token check that Pyramid normally enforces for every unsafe HTTP method. Every view that relies on the default is now exposed to cross-site request forgery. Set require_csrf=True (or drop the override) to bring the project-wide protection back.

CWE: CWE-352 · OWASP: A01:2021, A01:2025

Severity Category

Pyramid CSRF Origin Check Disabled

Rule ID: pyramid-csrf-origin-check-disabled

Description: Setting check_origin=False on @view_config(...) suppresses the Referer/Origin verification for this single view, so cross-site requests are accepted as long as they carry a CSRF token. Unless the CSRF storage policy is explicitly hardened, this widens the attack surface. Restore the default by passing check_origin=True or removing the keyword.

CWE: CWE-352 · OWASP: A01:2021, A01:2025

Severity Category

Pyramid CSRF Origin Check Disabled Globally

Rule ID: pyramid-csrf-origin-check-disabled-globally

Description: A global call to Configurator.set_default_csrf_options(check_origin=False) turns off the Referer/Origin header validation that Pyramid normally runs for every unsafe HTTP method. With an insecure CSRF storage policy this leaves all views unprotected against cross-site request forgery. Re-enable it by setting check_origin=True or by removing the keyword entirely.

CWE: CWE-352 · OWASP: A01:2021, A01:2025

Severity Category

Pyramid Direct Use Of Response

Rule ID: pyramid-direct-use-of-response

Description: Attributes read from the Pyramid request object flow straight into pyramid.request.Response(...) or assignments such as request.response.body / .text / .unicode_body. The bytes are written to the client untouched, bypassing template-engine escaping and creating a reflected XSS sink. Route the output through a renderer like pyramid_jinja2 or pyramid.renderers so autoescaping can run.

CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025

Severity Category

Rule ID: pyramid-set-cookie-httponly-unsafe-default

Description: A view calls response.set_cookie(...) without supplying the httponly keyword, so Pyramid emits the cookie with the HttpOnly attribute disabled and leaves it readable from client-side JavaScript. If the cookie carries session or identity data, any XSS finding becomes a session-hijack vector. Add httponly=True to the call.

CWE: CWE-1004 · OWASP: A05:2021, A02:2025

Severity Category

Rule ID: pyramid-set-cookie-httponly-unsafe-value

Description: The view explicitly passes httponly=False to response.set_cookie(...), overriding Pyramid's safer behaviour and instructing the browser to make the cookie reachable through document.cookie. That gives any XSS payload direct access to the cookie value. Change the keyword to httponly=True.

CWE: CWE-1004 · OWASP: A05:2021, A02:2025

Severity Category

Rule ID: pyramid-set-cookie-samesite-unsafe-default

Description: response.set_cookie(...) is invoked without a samesite keyword, so the Pyramid cookie is shipped without the SameSite attribute and browsers continue to attach it on cross-site navigations. That keeps the door open to CSRF and cross-origin tracking. Pass samesite='Lax' (or 'Strict') when issuing the cookie.

CWE: CWE-1275 · OWASP: A01:2021, A01:2025

Severity Category

Rule ID: pyramid-set-cookie-samesite-unsafe-value

Description: The samesite keyword passed to response.set_cookie(...) is a value other than 'Lax', which weakens the cross-site protection that browsers apply to the cookie. Forged cross-origin requests can still attach it, enabling CSRF or leakage to embedding frames. Set the keyword to samesite='Lax' (or 'Strict').

CWE: CWE-1275 · OWASP: A01:2021, A01:2025

Severity Category

Rule ID: pyramid-set-cookie-secure-unsafe-default

Description: The view emits response.set_cookie(...) without the secure keyword, which means Pyramid omits the Secure attribute and browsers also send the cookie over plain-HTTP requests. Any network attacker on the path can capture it. Pass secure=True so the cookie is only transmitted on TLS connections.

CWE: CWE-614 · OWASP: A05:2021, A02:2025

Severity Category

Rule ID: pyramid-set-cookie-secure-unsafe-value

Description: response.set_cookie(...) is called with secure=False, explicitly stripping the Secure flag from the issued cookie. The browser will then send it over HTTP as well as HTTPS, exposing the value to interception. Switch the keyword to secure=True.

CWE: CWE-614 · OWASP: A05:2021, A02:2025

Severity Category

Pyramid Sqlalchemy SQL Injection

Rule ID: pyramid-sqlalchemy-sql-injection

Description: User-controlled data taken from the Pyramid request object is interpolated into a raw SQL fragment via str.format(...) (or another non-binding formatter) and then passed to SQLAlchemy clauses such as filter(...), order_by(...), group_by(...), having(...) or distinct(...). This produces a classic SQL-injection sink. Bind parameters with text("...").bindparams(...) so the values are sent to the database as parameters, not as SQL.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Disabled Cert Validation

Rule ID: disabled-cert-validation

Description: A requests HTTP method (get, post, put, etc.) is being called with verify=False, so urllib3 skips TLS certificate chain validation. This lets any machine-in-the-middle present a forged certificate and intercept or rewrite the traffic. Remove the override (or set verify=True) and use verify=<ca_bundle> if a custom CA is required.

CWE: CWE-295 · OWASP: A03:2017, A07:2021, A07:2025

Severity Category

No Auth Over HTTP

Rule ID: no-auth-over-http

Description: A requests.* call is sending an auth= credential to an http:// URL, meaning the username, password, or bearer token is transmitted in cleartext where any network observer can capture it. Switch the URL scheme to https:// (or use a properly TLS-terminated endpoint) so the credentials are encrypted in transit.

CWE: CWE-523 · OWASP: A02:2017, A02:2021, A04:2025

Severity Category

String Concat

Rule ID: string-concat

Description: A sh.<bin>(...) invocation is being passed a string built from concatenation, str.format, or an f-string. If any of the interpolated values are attacker controlled they can break the argument boundary and execute arbitrary shell logic. Pass each token as a discrete positional argument (e.g. sh.git("commit", "-m", msg)).

CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Avoid Sqlalchemy Text

Rule ID: avoid-sqlalchemy-text

Description: A string assembled with concatenation, f-string interpolation, str.format, or % formatting is reaching sqlalchemy.text(...), which submits the statement to the database verbatim. Any tainted segment becomes raw SQL and yields injection. Build the statement with sqlalchemy.text("... :param ...").bindparams(param=value) or use the Core expression language (select, and_, or_).

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Bad Operator In Filter

Rule ID: bad-operator-in-filter

Description: Python-level boolean operators (is, is not, and, or, not, in) inside a Model.query.filter(...) clause are evaluated by the interpreter, not translated into SQL, so the predicate effectively collapses to a constant. Replace them with their SQLAlchemy equivalents: ==, !=, sqlalchemy.and_, sqlalchemy.or_, sqlalchemy.not_, and Column.in_(...).

Severity Category

Batch Import

Rule ID: batch-import

Description: db.session.add(...) is being invoked inside a loop, producing one autoflush per iteration and many small INSERTs. For bulk loading prefer session.add_all([...]) or session.bulk_save_objects([...]) so the rows can be flushed in a single round-trip.

Severity Category

Delete Where No Execute

Rule ID: delete-where-no-execute

Description: A SQLAlchemy Table.delete().where(...) statement was built but never handed to connection.execute(...), so no rows are actually removed at runtime. Either pass the statement to connection.execute(...), or rewrite the call as a Query-style session.query(Model).filter(...).delete() which executes immediately.

Severity Category

Len All Count

Rule ID: len-all-count

Description: Calling len(query.all()) materialises every matching row into Python objects just to count them, dragging the whole result set across the wire. Replace it with query.count() so the count is computed in the database with a SELECT COUNT(*).

Severity Category

Sqlalchemy Execute Raw Query

Rule ID: sqlalchemy-execute-raw-query

Description: A statement built with +, %, str.format, or an f-string is being passed to connection.execute(...). The interpolated values bypass parameter binding, so any attacker-controlled segment is appended directly to the SQL text and runs unescaped. Use a parameterised sqlalchemy.text("... :p ...").bindparams(p=value) form or move the predicate into the Core/ORM expression language.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Sqlalchemy SQL Injection

Rule ID: sqlalchemy-sql-injection

Description: A raw SQL fragment formatted with a non-bindparams interpolation (typically str.format or f-string) is being passed to query.filter(...), query.distinct(...), query.group_by(...), query.having(...), or query.order_by(...). Because the function parameter is concatenated into the SQL text, callers can inject arbitrary statements. Switch to text("... :name ...").bindparams(name=value) so the values are passed as bound parameters.

CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025

Severity Category

Twiml Injection

Rule ID: twiml-injection

Description: Tainted data flows into the twiml= argument of Client.calls.create(...) without passing through xml.sax.saxutils.escape or html.escape. Because TwiML is parsed as XML by Twilio, the unescaped value can introduce extra <Say>, <Dial>, or <Redirect> verbs and hijack the call flow. Sanitise the input or build the TwiML with the twilio.twiml.VoiceResponse builder instead of string interpolation.

CWE: CWE-91 · OWASP: A03:2021, A05:2025

Severity Category

Ship Fast. Validate Smarter.Protect your reputation.

Cyclopt G2 profile

29A, Ptolemaion Street, Coho Building, Thessaloniki, Greece, Tel: +30 2310 471 030
Copyright © 2026 Cyclopt