#python

Rulesets (26)

Gitlab, Semgrep

Use Semgrep as a universal linter to identify vulnerabilities in your code base with the bandit (https://github.com/PyCQA/bandit) rule pack.

Gitlab

Leverage all Gitlab provided rules with the gitlab rulepack.

Gitlab, Semgrep

Use Semgrep as a universal linter to identify vulnerabilities in your code base with the bandit (https://github.com/PyCQA/bandit) rule pack.

Rules (626)

No author info

Insufficient permissions to view rule definition. This rule is only visible to logged in users. Log in to see this rule.

No author info

Insufficient permissions to view rule definition. This rule is only visible to logged in users. Log in to see this rule.

No author info

Insufficient permissions to view rule definition. This rule is only visible to logged in users. Log in to see this rule.

No author info

Using various methods to parse untrusted XML data is known to be vulnerable to XML attacks. Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is called.

No author info

'mark_safe()' is used to mark a string as "safe" for HTML output. This disables escaping and could therefore subject the content to XSS attacks. Use 'django.utils.html.format_html()' to build HTML for rendering instead.

profile photo of returntocorpreturntocorp

QuerySet.extra' does not provide safeguards against SQL injection and requires very careful use. SQL injection can lead to critical data being stolen by attackers. Instead of using '.extra', use the Django ORM and parameterized queries such as `People.objects.get(name='Bob')`.

profile photo of returntocorpreturntocorp

Detected use of the 'none' algorithm in a JWT token. The 'none' algorithm assumes the integrity of the token has already been verified. This would allow a malicious actor to forge a JWT token that will automatically be verified. Do not explicitly use the 'none' algorithm. Instead, use an algorithm such as 'HS256'.

No author info

The application was found using an unsafe version of `yaml` load which is vulnerable to deserialization attacks. Deserialization attacks exploit the process of reading serialized data and turning it back into an object. By constructing malicious objects and serializing them, an adversary may attempt to: - Inject code that is executed upon object construction, which occurs during the deserialization process. - Exploit mass assignment by including fields that are not normally a part of the serialized data but are read in during deserialization. To remediate this issue, use `safe_load()` or call `yaml.load()` with the `Loader` argument set to `yaml.SafeLoader`. Example loading YAML using `safe_load`: ``` import yaml # Use safe_load to load data into an intermediary object intermediary_object = yaml.safe_load("""user: name: 'test user'""" ) # Create our real object, copying over only the necessary fields user_object = {'user': { # Assign the deserialized data from intermediary object 'name': intermediary_object['user']['name'], # Add in protected data in object definition (or set it from a class constructor) 'is_admin': False, } } # Work with user_object # ... ``` For more details on deserialization attacks in general, see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html

No author info

Using various methods to parse untrusted XML data is known to be vulnerable to XML attacks. Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is called.

profile photo of returntocorpreturntocorp

The `flask.request.host` is used to construct an HTTP request. This can lead to host header injection issues. Vulnerabilities that generally occur due to this issue are authentication bypasses, password reset issues, Server-Side-Request-Forgery (SSRF), and many more. It is recommended to validate the URL before passing it to a request library, or using application logic such as authentication or password resets.

profile photo of returntocorpreturntocorp

Detected user input flowing into a manually constructed HTML string. You may be accidentally bypassing secure methods of rendering HTML by manually constructing HTML and this could create a cross-site scripting vulnerability, which could let attackers steal sensitive user data. To be sure this is safe, check that the HTML is rendered safely. Otherwise, use templates (`flask.render_template`) which will safely render HTML instead.

No author info

The application was found using `cPickle` which is vulnerable to deserialization attacks. Deserialization attacks exploit the process of reading serialized data and turning it back into an object. By constructing malicious objects and serializing them, an adversary may attempt to: - Inject code that is executed upon object construction, which occurs during the deserialization process. - Exploit mass assignment by including fields that are not normally a part of the serialized data but are read in during deserialization. Consider safer alternatives such as serializing data in the JSON format. Ensure any format chosen allows the application to specify exactly which object types are allowed to be deserialized. To protect against mass assignment, only allow deserialization of the specific fields that are required. If this is not easily done, consider creating an intermediary type that can be serialized with only the necessary fields exposed. Example JSON deserializer using an intermediary type that is validated against a schema to ensure it is safe from mass assignment: ``` import jsonschema # Create a schema to validate our user-supplied input against # an intermediary object intermediary_schema = { "type" : "object", "properties" : { "name": {"type" : "string"} }, "required": ["name"], # Protect against random properties being added to the object "additionalProperties": False, } # If a user attempted to add "'is_admin': True" it would cause a validation error intermediary_object = {'name': 'test user'} try: # Validate the user supplied intermediary object against our schema jsonschema.validate(instance=intermediary_object, schema=intermediary_schema) user_object = {'user': { # Assign the deserialized data from intermediary object 'name': intermediary_object['name'], # Add in protected data in object definition (or set it from a class constructor) 'is_admin': False, } } # Work with the user_object except jsonschema.exceptions.ValidationError as ex: # Gracefully handle validation errors # ... ``` For more details on deserialization attacks in general, see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html

No author info

The application may be vulnerable to a path traversal if it extracts untrusted archive files. This vulnerability is colloquially known as 'Zip Slip'. Archive files may contain folders which, when extracted, may write outside of the intended directory. This is exploited by including path traversal characters such as `../../other/directory` to overwrite or place files in system or application directories. Extra care must be taken when extracting archive files as there are numerous concerns: - If possible, generate unique filenames instead of using the archives file names, as it may be possible for users to overwrite files if the filenames are the same. - Validate file paths are written with a prefixed, known trusted directory. - Only process regular files and not symbolic links, as some applications may attempt to read/follow the symbolic link, leading to arbitrary file read / write vulnerabilities. Example of securely processing an archive file: ``` import tarfile import uuid # import os tar = tarfile.open('some.tar') # Max number of allowed files in our archive max_files = 10 # Max size for all files in archive max_size = 1024 * 1024 * 10 # 10MB # Max size per file in archive max_file_size = 1024 * 1024 # 1MB # Validate number of files in archive if len(tar.getmembers()) > max_files: raise Exception("Too many files in archive") total_size = 0 # Loop over all files to see if we exceed max size # if so, do not process any of them. for f in tar.getmembers(): total_size += f.size if total_size >= max_size: raise Exception("Archive files exceeded max file size") # Iterate over files now that we know the total size is within limits for f in tar.getmembers(): # Internally this calls TarInfo.isreg() which ensures # the file is a regular file and not a sym link or directory if not f.isfile(): continue # Optional, set a limit on each file size if f.size > max_file_size: raise Exception(f"File {f.name} too large: {f.size}") # If original names are required, ensure that only the # filename is used: # filename = os.path.basename(f.name) # More secure, generate a UUID4 value instead filename = uuid.uuid4().hex # Reset the archive filename to the basename # Newer versions of python (3.11.4+) should use: # new_tar = old_tar.replace(name=...new name...) f.name = filename # Extract the file into a restricted directory, with our # own user's attributes, not the file from the archive tar.extract(f, '/opt/app/restricted/', set_attrs=False) ``` For more information on tarfile see: - https://docs.python.org/3/library/tarfile.html

No author info

An IPMI-related module is being imported. IPMI is considered insecure. Use an encrypted protocol.

No author info

Detected SHA1 hash algorithm which is considered insecure. SHA1 is not collision resistant and is therefore not suitable as a cryptographic signature. Use SHA256 or SHA3 instead.

No author info

functions are being called. FTP is considered insecure. Use SSH/SFTP/SCP orsome other encrypted protocol

profile photo of returntocorpreturntocorp

Found a Flask cookie without secure, httponly, or samesite correctly set. Flask cookies should be handled securely by setting secure=True, httponly=True, and samesite='Lax' in response.set_cookie(...). If these parameters are not properly set, your cookies are not properly protected and are at risk of being stolen by an attacker. Include the 'secure=True', 'httponly=True', samesite='Lax' arguments or set these to be true in the Flask configuration.

profile photo of returntocorpreturntocorp

User data flows into the host portion of this manually-constructed URL. This could allow an attacker to send data to their own server, potentially exposing sensitive data such as cookies or authorization information sent with this request. They could also probe internal servers or other resources that the server runnig this code can access. (This is called server-side request forgery, or SSRF.) Do not allow arbitrary hosts. Instead, create an allowlist for approved hosts hardcode the correct host.

No author info

Hardcoded password is used as a default argument to `$FUNC`. This could be dangerous if a real password is not supplied.

No author info

SQL Injection is a critical vulnerability that can lead to data or system compromise. By dynamically generating SQL query strings, user input may be able to influence the logic of the SQL statement. This could lead to an adversary accessing information they should not have access to, or in some circumstances, being able to execute OS functionality or code. Replace all dynamically generated SQL queries with parameterized queries. In situations where dynamic queries must be created, never use direct user input, but instead use a map or dictionary of valid values and resolve them using a user supplied key. For example, some database drivers do not allow parameterized queries for `>` or `<` comparison operators. In these cases, do not use a user supplied `>` or `<` value, but rather have the user supply a `gt` or `lt` value. The alphabetical values are then used to look up the `>` and `<` values to be used in the construction of the dynamic query. The same goes for other queries where column or table names are required but cannot be parameterized. The `QuerySet.extra` API method will be deprecated as it a source of SQL Injection vulnerabilities and other problems. This method is especially risky as callers will need to do their own escaping of any parameters that come from user-supplied information. To remediate this issue, do not use `extra` but use other `QuerySet` methods to achieve the same goals. If for some reason this is not feasible, consider using the `RawSQL` method and making sure that all arguments, including user-supplied ones, are only used in `params` While not recommended due to [potential SQL Injection](https://docs.djangoproject.com/en/4.2/ref/models/expressions/#raw-sql-expressions), below is an example using `RawSQL`, passing in user-supplied data as a `param` which will escape the input: ``` # If dealing with integer based user input, restrict the values to integers only using the # path configuration: path('<int:user_supplied_id>/someview/', views.some_view, name='someview'), # views.py def some_view(request, user_supplied_id): # Never use string interpolation in the `sql` parameter. # Never quote the `%s` string format such as `... where id='%s'` as this could lead to SQL Injection. # Pass the user supplied data only in the `params` parameter. for obj in DBObject.objects.all().annotate( val=RawSQL(sql="select id from some_secondary_table where id=%s", params=[user_supplied_id])): # Work with the results from the query # ... ``` For more information on QuerySet see: - https://docs.djangoproject.com/en/4.2/ref/models/querysets/#queryset-api For more information on SQL Injection see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html

No author info

SQL Injection is a critical vulnerability that can lead to data or system compromise. By dynamically generating SQL query strings, user input may be able to influence the logic of the SQL statement. This could lead to an adversary accessing information they should not have access to, or in some circumstances, being able to execute OS functionality or code. Replace all dynamically generated SQL queries with parameterized queries. In situations where dynamic queries must be created, never use direct user input, but instead use a map or dictionary of valid values and resolve them using a user supplied key. For example, some database drivers do not allow parameterized queries for `>` or `<` comparison operators. In these cases, do not use a user supplied `>` or `<` value, but rather have the user supply a `gt` or `lt` value. The alphabetical values are then used to look up the `>` and `<` values to be used in the construction of the dynamic query. The same goes for other queries where column or table names are required but cannot be parameterized. To remediate this issue, do not use `raw` or `RawSQL` but use other `QuerySet` methods to achieve the same goals. If for some reason this is not feasible, ensure calls including user-supplied data pass it in to the `params` parameter of the `RawSQL` method. While not recommended due to [potential SQL Injection](https://docs.djangoproject.com/en/4.2/ref/models/expressions/#raw-sql-expressions), below is an example using `RawSQL`, passing in user-supplied data as a `param` which will escape the input: ``` # If dealing with integer based user input, restrict the values to integers only using the # path configuration: path('<int:user_supplied_id>/someview/', views.some_view, name='someview'), # views.py def some_view(request, user_supplied_id): # Never use string interpolation in the `sql` parameter. # Never quote the `%s` string format such as `... where id='%s'` as this could lead to SQL Injection. # Pass the user supplied data only in the `params` parameter. for obj in DBObject.objects.all().annotate( val=RawSQL(sql="select id from some_secondary_table where id=%s", params=[user_supplied_id])): # Work with the results from the query # ... ``` For more information on QuerySet see: - https://docs.djangoproject.com/en/4.2/ref/models/querysets/#queryset-api For more information on SQL Injection see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html

No author info

The application was found using mako templates without `default_filters` being passed to the `Template` or `TemplateLookup` constructors. If using in the context of HTML, this could lead to Cross-Site Scripting (XSS) attacks when rendering with user-supplied input. Unfortunately, Jinja2 does not support context-aware escaping, meaning it is insufficient to protect against XSS for the various web contexts. It is important to encode the data depending on the specific context it is used in. There are at least six context types: - Inside HTML tags `<div>context 1</div>` - Inside attributes: `<div class="context 2"></div>` - Inside event attributes `<button onclick="context 3">button</button>` - Inside script blocks: `<script>var x = "context 4"</script>` - Unsafe element HTML assignment: `element.innerHTML = "context 5"` - Inside URLs: `<iframe src="context 6"></iframe><a href="context 6">link</a>` Script blocks alone have multiple ways they need to be encoded. Extra care must be taken if user input is ever output inside of script tags. User input that is displayed within the application must be encoded, sanitized or validated to ensure it cannot be treated as HTML or executed as Javascript code. Care must also be taken to not mix server-side templating with client-side templating, as the server-side templating will not encode things like {{ 7*7 }} which may execute client-side templating features. It is _NOT_ advised to encode user input prior to inserting into a data store. The data will need to be encoded depending on context of where it is output. It is much safer to force the displaying system to handle the encoding and not attempt to guess how it should be encoded. To handle different contexts, one approach would be to write custom mako filters. Below is an example that escapes or encodes links and potentially malicious script, note this does not include other contexts such as CSS or attributes: ``` # filters.py module: def escape_link(value): bad_link = "#JinjatmplZ" # Block any values that start with // as that could be used to inject # links to third party pages see: https://en.wikipedia.org/wiki/Wikipedia:Protocol-relative_URL if value.startswith('//'): return bad_link # Only allow relative links # if you want to allow links that start with http or ws replace with below: # if not value.startswith('/'): and not value.startswith('http') and not value.startswith('ws') if not value.startswith('/'): return bad_link return value # Create a replacement table js_replacement = str.maketrans({ '\0': "\\u0000", '\t': "\\t", '\n': "\\n", '\v': "\\u000b", '\f': "\\f`", '\r': "\\r", '"': "\\u0022", '`': "\\u0060", '&': "\\u0026", '\'': "\\u0027", '+': "\\u002b", '/': "\\/", '<': "\\u003c", '>': "\\u003e", '\\': "\\\\", '(': "\\u0028", ')': "\\u0029", }) def escape_js(value): # Escape the input for use in <script> context, USE WITH CAUTION # It is strongly recommended to never pass user-supplied input to # the JavaScript context. # Translate any potential characters using our translation table return value.translate(js_replacement) ##################################################################### # main module: # ##################################################################### from mako.template import Template # Define our template, note the calls to our custom filters depending # on context template_text = """ <!DOCTYPE html> <html lang="en"> <head> <title>My Webpage</title> </head> <body> <h1>My Webpage</h1> ${html_context} <a href="${link_context | escape_link}">link</a> <script>${script_context | escape_js}</script> </body> </html> """ # Load our template with default filters and our imported filters for # usage in template files t = Template(template_text, # By default enable the html filter with 'h' default_filters=['h'], # Import our custom filters imports=["from filters import escape_link, escape_js"]) # Render our template print(t.render(html_context="<img src=x onerror=alert(1)>", link_context="/# onclick=alert(1)<script>alert(1)</script>", script_context="alert(1)<img src=x onerror=alert(1)>",) ) ```

profile photo of returntocorpreturntocorp

Detected subprocess function '$LOOP.subprocess_exec' with argument tainted by `event` object. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.

profile photo of returntocorpreturntocorp

Detected SQL statement that is tainted by `event` object. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can use parameterized statements like so: `cursor.execute('SELECT * FROM projects WHERE status = %s', ('active'))`

profile photo of returntocorpreturntocorp

Detected SQL statement that is tainted by `event` object. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can use parameterized statements like so: `cursor.execute('SELECT * FROM projects WHERE status = %s', 'active')`

profile photo of returntocorpreturntocorp

Detected SQL statement that is tainted by `event` object. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can use parameterized statements like so: `cursor.execute('SELECT * FROM projects WHERE status = %s', 'active')`

profile photo of returntocorpreturntocorp

Detected SQL statement that is tainted by `event` object. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can use parameterized statements like so: `cursor.execute('SELECT * FROM projects WHERE status = %s', ('active'))`

profile photo of returntocorpreturntocorp

Detected SQL statement that is tainted by `event` object. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can use parameterized statements like so: `cursor.execute('SELECT * FROM projects WHERE status = ?', 'active')`

profile photo of returntocorpreturntocorp

Detected the use of 'RawSQL' or 'raw' indicating the execution of a non-parameterized SQL query. This could lead to a SQL injection and therefore protected information could be leaked. Instead, use Django ORM and parameterized queries before raw SQL. An example of using the Django ORM is: `People.objects.get(name='Bob')`

profile photo of returntocorpreturntocorp

Django cookies should be handled securely by setting secure=True, httponly=True, and samesite='Lax' in response.set_cookie(...). If your situation calls for different settings, explicitly disable the setting. If you want to send the cookie over http, set secure=False. If you want to let client-side JavaScript read the cookie, set httponly=False. If you want to attach cookies to requests for external sites, set samesite=None.

profile photo of returntocorpreturntocorp

Detected Django filters flagged with 'is_safe'. 'is_safe' tells Django not to apply escaping on the value returned by this filter (although the input is escaped). Used improperly, 'is_safe' could expose your application to cross-site scripting (XSS) vulnerabilities. Ensure this filter does not 1) add HTML characters, 2) remove characters, or 3) use external data in any way. Consider instead removing 'is_safe' and explicitly marking safe content with 'mark_safe()'.

profile photo of returntocorpreturntocorp

Passing a formatted string as first parameter to `format_html` disables the proper encoding of variables. Any HTML in the first parameter is not encoded. Using a formatted string as first parameter obscures which parameters are encoded. Correct use of `format_html` is passing a static format string as first parameter, and the variables to substitute as subsequent parameters.

profile photo of returntocorpreturntocorp

The `__html__` method indicates to the Django template engine that the value is 'safe' for rendering. This means that normal HTML escaping will not be applied to the return value. This exposes your application to cross-site scripting (XSS) vulnerabilities. If you need to render raw HTML, consider instead using `mark_safe()` which more clearly marks the intent to render raw HTML than a class with a magic method.

profile photo of returntocorpreturntocorp

Found user data in a call to 'exec'. This is extremely dangerous because it can enable an attacker to execute arbitrary remote code on the system. Instead, refactor your code to not use 'eval' and instead use a safe library for the specific functionality you need.

profile photo of returntocorpreturntocorp

Detected user input entering a `subprocess` call unsafely. This could result in a command injection vulnerability. An attacker could use this vulnerability to execute arbitrary commands on the host, which allows them to download malware, scan sensitive data, or run any command they wish on the server. Do not let users choose the command to run. In general, prefer to use Python API versions of system commands. If you must use subprocess, use a dictionary to allowlist a set of commands.

profile photo of returntocorpreturntocorp

Detected user input into a generated CSV file using the built-in `csv` module. If user data is used to generate the data in this file, it is possible that an attacker could inject a formula when the CSV is imported into a spreadsheet application that runs an attacker script, which could steal data from the importing user or, at worst, install malware on the user's computer. `defusedcsv` is a drop-in replacement with the same API that will attempt to mitigate formula injection attempts. You can use `defusedcsv` instead of `csv` to safely generate CSVs.

profile photo of returntocorpreturntocorp

Mass assignment detected. This can result in assignment to model fields that are unintended and can be exploited by an attacker. Instead of using '**request.$W', assign each field you want to edit individually to prevent mass assignment. You can read more about mass assignment at https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html.

profile photo of returntocorpreturntocorp

Data from request ($DATA) is passed to redirect(). This is an open redirect and could be exploited. Ensure you are redirecting to safe URLs by using django.utils.http.is_safe_url(). See https://cwe.mitre.org/data/definitions/601.html for more information.

profile photo of returntocorpreturntocorp

Detected user input flowing into a manually constructed HTML string. You may be accidentally bypassing secure methods of rendering HTML by manually constructing HTML and this could create a cross-site scripting vulnerability, which could let attackers steal sensitive user data. To be sure this is safe, check that the HTML is rendered safely. Otherwise, use templates (`django.shortcuts.render`) which will safely render HTML instead.

profile photo of returntocorpreturntocorp

Found user-controlled request data being passed into a file open, which is them passed as an argument into the FileResponse. This is dangerous because an attacker could specify an arbitrary file to read, which could result in leaking important data. Be sure to validate or sanitize the user-inputted filename in the request data before using it in FileResponse.

profile photo of returntocorpreturntocorp

Found user-controlled request data passed into '.write(...)'. This could be dangerous if a malicious actor is able to control data into sensitive files. For example, a malicious actor could force rolling of critical log files, or cause a denial-of-service by using up available disk space. Instead, ensure that request data is properly escaped or sanitized.

profile photo of returntocorpreturntocorp

Data that is possible user-controlled from a python request is passed to `raw()`. This could lead to SQL injection and attackers gaining access to protected information. Instead, use django's QuerySets, which are built with query parameterization and therefore not vulnerable to sql injection. For example, you could use `Entry.objects.filter(date=2006)`.

profile photo of returntocorpreturntocorp

Data from request object is passed to a new server-side request. This could lead to a server-side request forgery (SSRF). To mitigate, ensure that schemes and hosts are validated against an allowlist, do not forward the response to the user, and ensure proper authentication and transport-layer security in the proxied request. See https://owasp.org/www-community/attacks/Server_Side_Request_Forgery to learn more about SSRF vulnerabilities.

profile photo of returntocorpreturntocorp

Detected user input used to manually construct a SQL string. This is usually bad practice because manual construction could accidentally result in a SQL injection. An attacker could use a SQL injection to steal or modify contents of the database. Instead, use a parameterized query which is available by default in most database engines. Alternatively, consider using the Django object-relational mappers (ORM) instead of raw SQL queries.

profile photo of returntocorpreturntocorp

User data flows into the host portion of this manually-constructed URL. This could allow an attacker to send data to their own server, potentially exposing sensitive data such as cookies or authorization information sent with this request. They could also probe internal servers or other resources that the server runnig this code can access. (This is called server-side request forgery, or SSRF.) Do not allow arbitrary hosts. Instead, create an allowlist for approved hosts hardcode the correct host.

profile photo of returntocorpreturntocorp

Found user input going directly into typecast for bool(), float(), or complex(). This allows an attacker to inject Python's not-a-number (NaN) into the typecast. This results in undefind behavior, particularly when doing comparisons. Either cast to a different type, or add a guard checking for all capitalizations of the string 'nan'.

profile photo of returntocorpreturntocorp

Detected user input into a generated CSV file using the built-in `csv` module. If user data is used to generate the data in this file, it is possible that an attacker could inject a formula when the CSV is imported into a spreadsheet application that runs an attacker script, which could steal data from the importing user or, at worst, install malware on the user's computer. `defusedcsv` is a drop-in replacement with the same API that will attempt to mitigate formula injection attempts. You can use `defusedcsv` instead of `csv` to safely generate CSVs.

profile photo of returntocorpreturntocorp

Found user input going directly into typecast for bool(), float(), or complex(). This allows an attacker to inject Python's not-a-number (NaN) into the typecast. This results in undefind behavior, particularly when doing comparisons. Either cast to a different type, or add a guard checking for all capitalizations of the string 'nan'.

profile photo of returntocorpreturntocorp

Detected user input entering a `subprocess` call unsafely. This could result in a command injection vulnerability. An attacker could use this vulnerability to execute arbitrary commands on the host, which allows them to download malware, scan sensitive data, or run any command they wish on the server. Do not let users choose the command to run. In general, prefer to use Python API versions of system commands. If you must use subprocess, use a dictionary to allowlist a set of commands.

profile photo of returntocorpreturntocorp

Detected user input used to manually construct a SQL string. This is usually bad practice because manual construction could accidentally result in a SQL injection. An attacker could use a SQL injection to steal or modify contents of the database. Instead, use a parameterized query which is available by default in most database engines. Alternatively, consider using an object-relational mapper (ORM) such as SQLAlchemy which will protect your queries.

profile photo of returntocorpreturntocorp

Flask response reflects unsanitized user input. This could lead to a cross-site scripting vulnerability (https://owasp.org/www-community/attacks/xss/) in which an attacker causes arbitrary code to be executed in the user's browser. To prevent, please sanitize the user input, e.g. by rendering the response in a Jinja2 template (see considerations in https://flask.palletsprojects.com/en/1.0.x/security/).

profile photo of returntocorpreturntocorp

Detected the use of exec(). exec() can be dangerous if used to evaluate dynamic content. If this content can be input from outside the program, this may be a code injection vulnerability. Ensure evaluated content is not definable by external sources.

profile photo of returntocorpreturntocorp

The HTTPSConnection API has changed frequently with minor releases of Python. Ensure you are using the API for your version of Python securely. For example, Python 3 versions prior to 3.4.3 will not verify SSL certificates by default. See https://docs.python.org/3/library/http.client.html#http.client.HTTPSConnection for more information.

profile photo of returntocorpreturntocorp

Because portions of the logging configuration are passed through eval(), use of this function may open its users to a security risk. While the function only binds to a socket on localhost, and so does not accept connections from remote machines, there are scenarios where untrusted code could be run under the account of the process which calls listen(). To avoid this happening, use the `verify()` argument to `listen()` to prevent unrecognized configurations.

profile photo of returntocorpreturntocorp

The marshal module is not intended to be secure against erroneous or maliciously constructed data. Never unmarshal data received from an untrusted or unauthenticated source. See more details: https://docs.python.org/3/library/marshal.html?highlight=security

profile photo of returntocorpreturntocorp

Detected usage of re.compile with an inefficient regular expression. This can lead to regular expression denial of service, which can result in service down time. Instead, check all regexes or use safer alternatives such as pyre2.

profile photo of returntocorpreturntocorp

Detected string concatenation with a non-literal variable in a pg8000 Python SQL statement. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can create parameterized queries like so: 'conn.run("SELECT :value FROM table", value=myvalue)'. You can also create prepared statements with 'conn.prepare': 'conn.prepare("SELECT (:v) FROM table")'

profile photo of returntocorpreturntocorp

Detected string concatenation with a non-literal variable in a psycopg2 Python SQL statement. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can use prepared statements by creating a 'sql.SQL' string. You can also use the pyformat binding style to create parameterized queries. For example: 'cur.execute(SELECT * FROM table WHERE name=%s, user_input)'

profile photo of returntocorpreturntocorp

Detected the generation of a CSV file using the built-in `csv` module. If user data is used to generate the data in this file, it is possible that an attacker could inject a formula when the CSV is imported into a spreadsheet application that runs an attacker script, which could steal data from the importing user or, at worst, install malware on the user's computer. `defusedcsv` is a drop-in replacement with the same API that will attempt to mitigate formula injection attempts. You can use `defusedcsv` instead of `csv` to safely generate CSVs.

profile photo of returntocorpreturntocorp

Distinct, Having, Group_by, Order_by, and Filter in SQLAlchemy can cause sql injections if the developer inputs raw SQL into the before-mentioned clauses. This pattern captures relevant cases in which the developer inputs raw SQL into the distinct, having, group_by, order_by or filter clauses and injects user-input into the raw SQL with any function besides "bindparams". Use bindParams to securely bind user-input to SQL statements.

profile photo of returntocorpreturntocorp

This code contains bidirectional (bidi) characters. While this is useful for support of right-to-left languages such as Arabic or Hebrew, it can also be used to trick language parsers into executing code in a manner that is different from how it is displayed in code editing and review tools. If this is not what you were expecting, please review this code in an editor that can reveal hidden Unicode characters.

profile photo of returntocorpreturntocorp

Detected the use of eval(). eval() can be dangerous if used to evaluate dynamic content. If this content can be input from outside the program, this may be a code injection vulnerability. Ensure evaluated content is not definable by external sources.

profile photo of returntocorpreturntocorp

Detected user input flowing into a manually constructed HTML string. You may be accidentally bypassing secure methods of rendering HTML by manually constructing HTML and this could create a cross-site scripting vulnerability, which could let attackers steal sensitive user data. To be sure this is safe, check that the HTML is rendered safely. Otherwise, use templates which will safely render HTML instead.

profile photo of returntocorpreturntocorp

Data from request is passed to redirect(). This is an open redirect and could be exploited. Consider using 'url_for()' to generate links to known locations. If you must use a URL to unknown pages, consider using 'urlparse()' or similar and checking if the 'netloc' property is the same as your site's host name. See the references for more information.

profile photo of returntocorpreturntocorp

Use tempfile.NamedTemporaryFile instead. From the official Python documentation: THIS FUNCTION IS UNSAFE AND SHOULD NOT BE USED. The file name may refer to a file that did not exist at some point, but by the time you get around to creating it, someone else may have beaten you to the punch.

profile photo of returntocorpreturntocorp

Detected use of `exit`. Use `sys.exit` over the python shell `exit` built-in. `exit` is a helper for the interactive shell and may not be available on all Python implementations.

No author info

The Blowfish encryption algorithm was meant as a drop-in replacement for DES and was created in 1993. Smaller key sizes may make the ciphertext vulnerable to [birthday attacks](https://en.wikipedia.org/wiki/Birthday_attack). While no known attacks against Blowfish exist, it should never be used to encrypt files over 4GB in size. If possible consider using ChaCha20Poly1305 or AES-GCM instead of Blowfish. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

DES, TripleDES, RC2 and RC4 are all considered broken or insecure cryptographic algorithms. Newer algorithms apply message integrity to validate ciphertext has not been tampered with. Consider using `ChaCha20Poly1305` instead as it is easier and faster than the alternatives such as `AES-256-GCM`. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

DES, TripleDES, RC2 and RC4 are all considered broken or insecure cryptographic algorithms. Newer algorithms apply message integrity to validate ciphertext has not been tampered with. Consider using `ChaCha20Poly1305` instead as it is easier and faster than the alternatives such as `AES-256-GCM`. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

DES, TripleDES, RC2 and RC4 are all considered broken or insecure cryptographic algorithms. Newer algorithms apply message integrity to validate ciphertext has not been tampered with. Consider using `ChaCha20Poly1305` instead as it is easier and faster than the alternatives such as `AES-256-GCM`. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was found using the `xor` algorithm, which can be trivially decoded. Newer algorithms apply message integrity to validate ciphertext has not been tampered with. Consider using `ChaCha20Poly1305` instead as it is easier and faster than the alternatives such as `AES-256-GCM`. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application is generating an RSA key that is less than the recommended 2048 bits. The National Institute of Standards and Technology (NIST) deprecated signing Digital Certificates that contained RSA Public Keys of 1024 bits in December 2010. While 1024-bit RSA keys have not been factored yet, advances in compute may make it possible in the near future. Consider upgrading to the newer asymmetric algorithm such as `X25519` which handles the complexities of generating key pairs and choosing correct key sizes for you: ``` from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey # Generate a private key for use in the exchange. private_key = X25519PrivateKey.generate() # Work with private key/exchange with a peer's # public key to created a shared and derived key # ... ``` Otherwise use a key size greater than 2048 when generating RSA keys: ``` from cryptography.hazmat.primitives.asymmetric import rsa # Generate a private key of 4096 bits private_key = rsa.generate_private_key( # do not change the exponent value from 65537 public_exponent=65537, key_size=4096, ) # Work with the private key to sign/encrypt data # ... ``` For more information on using the cryptography module see: - https://cryptography.io/en/latest

No author info

The application was found using an insufficient curve size for the Elliptical Cryptography (EC) asymmetric algorithm. NIST recommends using a key size of 224 or greater. To remediate this issue, replace the current key size with `ec.SECP384R1`, Example using `ec.SECP384R1`: ``` from cryptography.hazmat.primitives.asymmetric import ec # Generate an EC private key using SECP384R1 private_key = ec.generate_private_key( ec.SECP384R1() ) # Work with/sign data using the key # ... ``` For more information on the cryptography module's EC section see: - https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ec/

No author info

The application was found using an insecure or risky digest or signature algorithm. MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. It is strongly recommended that a standard digest algorithm be chosen instead as implementing a custom algorithm is prone to errors. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example of creating a SHA-384 hash using the `cryptography` package: ``` from cryptography.hazmat.primitives import hashes # Create a SHA384 digest digest = hashes.Hash(hashes.SHA384()) # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes result = digest.finalize() ``` For more information on secure password storage see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was found using an insecure or risky digest or signature algorithm. MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. It is strongly recommended that a standard digest algorithm be chosen instead as implementing a custom algorithm is prone to errors. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example of creating a SHA-384 hash using the `cryptography` package: ``` from cryptography.hazmat.primitives import hashes # Create a SHA384 digest digest = hashes.Hash(hashes.SHA384()) # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes result = digest.finalize() ``` For more information on secure password storage see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

DES, TripleDES, RC2 and RC4 are all considered broken or insecure cryptographic algorithms. Newer algorithms apply message integrity to validate ciphertext has not been tampered with. Consider using `ChaCha20Poly1305` instead as it is easier and faster than the alternatives such as `AES-256-GCM`. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The Blowfish encryption algorithm was meant as a drop-in replacement for DES and was created in 1993. Smaller key sizes may make the ciphertext vulnerable to [birthday attacks](https://en.wikipedia.org/wiki/Birthday_attack). While no known attacks against Blowfish exist, it should never be used to encrypt files over 4GB in size. If possible consider using ChaCha20Poly1305 or AES-GCM instead of Blowfish. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The IDEA encryption algorithm was meant as a drop-in replacement for DES and was created in 1991. A number of [vulnerabilities and exploits](https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm#Security) have been identified to work against IDEA and it is no longer recommended. If possible consider using ChaCha20Poly1305 or AES-GCM instead of Blowfish. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was found using an insecure or risky digest or signature algorithm. MD2, MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example of creating a SHA-384 hash using the `cryptography` package: ``` from cryptography.hazmat.primitives import hashes # Create a SHA384 digest digest = hashes.Hash(hashes.SHA384()) # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes result = digest.finalize() ``` For more information on secure password storage see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was found using an insecure or risky digest or signature algorithm. MD2, MD4, MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example of creating a SHA-384 hash using the `cryptography` package: ``` from cryptography.hazmat.primitives import hashes # Create a SHA384 digest digest = hashes.Hash(hashes.SHA384()) # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes result = digest.finalize() ``` For more information on secure password storage see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was found using an insecure or risky digest or signature algorithm. MD2, MD4, MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example of creating a SHA-384 hash using the `cryptography` package: ``` from cryptography.hazmat.primitives import hashes # Create a SHA384 digest digest = hashes.Hash(hashes.SHA384()) # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes result = digest.finalize() ``` For more information on secure password storage see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was detected importing `pycrypto`. This package has been deprecated as it contains security vulnerabilities. To remediate this issue, consider using the [cryptography](https://cryptography.io/) package instead.

No author info

The application was found using `dill` which is vulnerable to deserialization attacks. Deserialization attacks exploit the process of reading serialized data and turning it back into an object. By constructing malicious objects and serializing them, an adversary may attempt to: - Inject code that is executed upon object construction, which occurs during the deserialization process. - Exploit mass assignment by including fields that are not normally a part of the serialized data but are read in during deserialization. Consider safer alternatives such as serializing data in the JSON format. Ensure any format chosen allows the application to specify exactly which object types are allowed to be deserialized. To protect against mass assignment, only allow deserialization of the specific fields that are required. If this is not easily done, consider creating an intermediary type that can be serialized with only the necessary fields exposed. Example JSON deserializer using an intermediary type that is validated against a schema to ensure it is safe from mass assignment: ``` import jsonschema # Create a schema to validate our user-supplied input against # an intermediary object intermediary_schema = { "type" : "object", "properties" : { "name": {"type" : "string"} }, "required": ["name"], # Protect against random properties being added to the object "additionalProperties": False, } # If a user attempted to add "'is_admin': True" it would cause a validation error intermediary_object = {'name': 'test user'} try: # Validate the user supplied intermediary object against our schema jsonschema.validate(instance=intermediary_object, schema=intermediary_schema) user_object = {'user': { # Assign the deserialized data from intermediary object 'name': intermediary_object['name'], # Add in protected data in object definition (or set it from a class constructor) 'is_admin': False, } } # Work with the user_object except jsonschema.exceptions.ValidationError as ex: # Gracefully handle validation errors # ... ``` For more details on deserialization attacks in general, see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html

No author info

The application was found calling the `eval` function with a non-literal variable. If the variable comes from user-supplied input, an adversary could compromise the entire system by executing arbitrary python code. To remediate this issue, remove all calls to `eval` and consider alternative methods for executing the necessary business logic. There is almost no safe method of calling `eval` with user-supplied input. If the application only needs to convert strings into objects, consider using `json.loads`. In some cases `ast.literal_eval` is recommended, but this should be avoided as it can still suffer from other issues such as the ability for malicious code to crash the python interpreter or application. Example using `json.loads`` to load in arbitrary data to create data structures: ``` # User supplied data as a blob of JSON user_supplied_data = """{"user": "test", "metadata": [1,2,3]}""" # Load the JSON user_object = json.loads(user_supplied_data) # Manually add protected properties _after_ loading, never before user_object["is_admin"] = False # Work with the object ```

No author info

Detected use of the wildcard character in a system call that spawns a shell.This subjects the wildcard to normal shell expansion, which can have unintended consequencesif there exist any non-standard file names. Consider a file named `-e sh script.sh`.

No author info

Starting a process with a shell; seems safe, but may be changed in the future, consider rewriting without shell

No author info

Starting a process with a shell; seems safe, but may be changed in the future, consider rewriting without shell

No author info

Unverified SSL context detected. This will permit insecure connections without `verifyingSSL` certificates. Use `ssl.create_default_context()` instead.

No author info

Found dynamic content when spawning a process. This is dangerous if externaldata can reach this function call because it allows a malicious actor toexecute commands. Ensure no external data reaches here.

No author info

Python possesses many mechanisms to invoke an external executable. However, doing so may present a security issue if appropriate care is not taken to sanitize any user provided or variable input. This plugin test is part of a family of tests built to check for process spawning and warn appropriately. Specifically, this test looks for the spawning of a subprocess without the use of a command shell. This type of subprocess invocation is not vulnerable to shell injection attacks, but care should still be taken to ensure validity of input.

No author info

Found `subprocess` function `$FUNC` with `shell=True`. This is dangerous because this call will spawn the command using a shell process. Doing so propagates current shell settings and variables, which makes it much easier for a malicious actor to execute commands. Use `shell=False` instead.

No author info

The application was found calling the `logging.config.listen`` function, which provides the ability to listen for external configuration files over a socket server. This listen socket parses part of the configuration and calls `eval` on the supplied configuration file. A local user, or an adversary who is able to exploit a Server Side Request Forgery (SSRF) attack to communicate over localhost, would be able to execute arbitrary code by passing in a logging config that contains python code. To remediate the issue, remove the call to `logging.config.listen` method. For more information on the listen functionality see: - https://docs.python.org/3/library/logging.config.html#logging.config.listen

No author info

Depending on the context, generating weak random numbers may expose cryptographic functions, which rely on these numbers, to be exploitable. When generating numbers for sensitive values such as tokens, nonces, and cryptographic keys, it is recommended that the `secrets` module be used instead. Example using the secrets module: ``` import secrets # Generate a secure random 64 byte array random_bytes = secrets.token_bytes(64) print(random_bytes) # Generate a secure random 64 byte array as a hex string random_bytes_hex = secrets.token_hex(64) # Generate a secure random 64 byte array base64 encoded for use in URLs random_string = secrets.token_urlsafe(64) ``` For more information on the `secrets` module see: - https://docs.python.org/3/library/secrets.html

No author info

The application was found using the `requests` module without configuring a timeout value for connections. This could lead to uncontrolled resource consumption where the application could run out of socket descriptors, effectively causing a Denial of Service (DoS). To remediate this issue, pass in a `timeout=` argument to each `requests` call. Example using a timeout for an HTTP GET request: ``` # Issue a GET request to https://example.com with a timeout of 10 seconds response = requests.get('https://example.com', timeout=10) # Work with the response object # ... ``` For more information on using the requests module see: - https://requests.readthedocs.io/en/latest/api/

No author info

SQL Injection is a critical vulnerability that can lead to data or system compromise. By dynamically generating SQL query strings, user input may be able to influence the logic of the SQL statement. This could lead to an adversary accessing information they should not have access to, or in some circumstances, being able to execute OS functionality or code. Replace all dynamically generated SQL queries with parameterized queries. In situations where dynamic queries must be created, never use direct user input, but instead use a map or dictionary of valid values and resolve them using a user supplied key. For example, some database drivers do not allow parameterized queries for `>` or `<` comparison operators. In these cases, do not use a user supplied `>` or `<` value, but rather have the user supply a `gt` or `lt` value. The alphabetical values are then used to look up the `>` and `<` values to be used in the construction of the dynamic query. The same goes for other queries where column or table names are required but cannot be parameterized. Example using `PreparedStatement` queries: ``` import sqlite3 # Create a new database (in memory) con = sqlite3.connect(":memory:") # Get a cursor from the connection cur = con.cursor() # Create a tuple of the value to be used in the parameterized query params = ('user-input',) # execute the statement, passing in the params for the value cur.execute("select name from sqlite_master where name = ?", params) # work with the result result = cur.fetchall() ``` For more information on SQL Injection see OWASP: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html

No author info

The application was found calling an SSL module with SSL or TLS protocols that have known deficiencies. It is strongly recommended that newer applications use TLS 1.2 or 1.3 and `SSLContext.wrap_socket`. If using the `pyOpenSSL` module, please note that it has been deprecated and the Python Cryptographic Authority strongly suggests moving to use the [pyca/cryptography](https://github.com/pyca/cryptography) module instead. To remediate this issue for the `ssl` module, create a new TLS context and pass in `ssl.PROTOCOL_TLS_CLIENT` for clients or `ssl.PROTOCOL_TLS_SERVER` for servers to the `ssl.SSLContext(...)` `protocol=` argument. When converting the socket to a TLS socket, use the new `SSLContext.wrap_socket` method instead. Example creating a TLS 1.3 client socket connection by using a newer version of Python (3.11.4) and the SSL module: ``` import ssl import socket # Create our initial socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: # Connect the socket sock.connect(('www.example.org', 443)) # Create a new SSLContext with protocol set to ssl.PROTOCOL_TLS_CLIENT # This will auto-select the highest grade TLS protocol version (1.3) context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT) # Load our a certificates for server certificate authentication context.load_verify_locations('cert.pem') # Create our TLS socket, and validate the server hostname matches with context.wrap_socket(sock, server_hostname="www.example.org") as tls_sock: # Send some bytes over the socket (HTTP request in this case)\ data = bytes('GET / HTTP/1.1\r\nHost: example.org\r\n\r\n', 'utf-8') sent_bytes = tls_sock.send(data) # Validate number of sent bytes # ... # Read the response resp = tls_sock.recv() # Work with the response # ... ``` For more information on the ssl module see: - https://docs.python.org/3/library/ssl.html For more information on pyca/cryptography and openssl see: - https://cryptography.io/en/latest/openssl/

No author info

The application was found creating a SSL context using the `_create_unverified_context`. This effectively disables the validation of server certificates. This allows for an adversary who is in between the application and the target host to intercept potentially sensitive information or transmit malicious data. To remediate this issue remove the call to `_create_unverified_context` and either create a default context using `ssl.create_default_context` or create a context with TLS 1.3. Example creating a TLS 1.3 client socket connection by using a newer version of Python (3.11.4) and the SSL module: ``` import ssl import socket # Create our initial socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: # Connect the socket sock.connect(('www.example.org', 443)) # Create a new SSLContext with protocol set to ssl.PROTOCOL_TLS_CLIENT # This will auto-select the highest grade TLS protocol version (1.3) context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT) # Load our a certificates for server certificate authentication context.load_verify_locations('cert.pem') # Create our TLS socket, and validate the server hostname matches with context.wrap_socket(sock, server_hostname="www.example.org") as tls_sock: # Send some bytes over the socket (HTTP request in this case)\ data = bytes('GET / HTTP/1.1\r\nHost: example.org\r\n\r\n', 'utf-8') sent_bytes = tls_sock.send(data) # Validate number of sent bytes # ... # Read the response resp = tls_sock.recv() # Work with the response # ... ``` Unverified SSL context detected. This will permit insecure connections without `verifyingSSL` certificates. Use `ssl.create_default_context()` instead.

No author info

The application was found creating files in shared system temporary directories (`/tmp` or `/var/tmp`) without using the `tempfile.TemporaryFile` function. Depending on how the application uses this temporary file, an attacker may be able to create symlinks that point to other files prior to the application creating or writing to the target file, leading to unintended files being created or overwritten. Example using `tempfile.TemporaryFile` to write a file: ``` import tempfile # Open a new temporary file using a context manager with tempfile.TemporaryFile() as fp: # Write some data to the temporary file fp.write(b'Some data') # Seek back to beginning of file fp.seek(0) # Read it data = fp.read() # File is automatically closed/removed once we exit the with context ``` For more information on alternative tempfile functions see: - https://docs.python.org/3/library/tempfile.html

No author info

The application was found passing in a non-literal value to the `urllib` methods which issue requests. `urllib` supports the `file://` scheme, which may allow an adversary who can control the URL value to read arbitrary files on the file system. To remediate this issue either hardcode the URLs being used in urllib or use the `requests` module instead. Example using the `requests` module to issue an HTTPS request: ``` import requests # Issue a GET request to https://example.com with a timeout of 10 seconds response = requests.get('https://example.com', timeout=10) # Work with the response object # ... ```

No author info

Pysnmp was detected using versions SNMPv1 or SNMPv2. SNPMv1 and SNMPv2 are insecure and should no longer be used as they do not offer encryption. If possible, query SNMP devices using SNMPv3 instead. Example querying a device using SNMPv3 with SHA-AES: ``` from pysnmp.hlapi import * # Create the snpm iterator iterator = getCmd( SnmpEngine(), # Configure using SHA AES UsmUserData('usr-sha-aes', 'authkey1', 'privkey1', authProtocol=USM_AUTH_HMAC96_SHA, privProtocol=USM_PRIV_CFB128_AES), UdpTransportTarget(('demo.snmplabs.com', 161)), ContextData(), ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)) ) ``` For more information on using SNMPv3 with `Pysnmp` see: - https://pysnmp.readthedocs.io/en/latest/examples/hlapi/v3arch/asyncore/sync/manager/cmdgen/snmp-versions.html#snmpv3-auth-sha-privacy-aes128

No author info

Pysnmp was detected using SNMPv3 without authentication or encryption protections enabled. When calling `UsmUserData`, the first argument should be in the format of `usr-<authtype>-<encryption type>`. To remediate this issue, the `UsmUserData` should be configured with `usr-sha-aes` for SHA authentication and AES encryption. Example querying a device using SNMPv3 with SHA-AES: ``` from pysnmp.hlapi import * # Create the snpm iterator iterator = getCmd( SnmpEngine(), # Configure using SHA AES UsmUserData('usr-sha-aes', 'authkey1', 'privkey1', authProtocol=USM_AUTH_HMAC96_SHA, privProtocol=USM_PRIV_CFB128_AES), UdpTransportTarget(('demo.snmplabs.com', 161)), ContextData(), ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)) ) ``` For more information on using SNMPv3 with `Pysnmp` see: - https://pysnmp.readthedocs.io/en/latest/examples/hlapi/v3arch/asyncore/sync/manager/cmdgen/snmp-versions.html#snmpv3-auth-sha-privacy-aes128

No author info

The application was found to ignore host keys. Host keys are important as they provide assurance that the client can prove that the host is trusted. By ignoring these host keys, it is impossible for the client to validate the connection is to a trusted host. To remediate this issue, remove the call to `set_missing_host_key_policy(...)` which sets the host key policy. Instead, load key files using either `load_system_host_keys` or `load_host_keys` to only allow known good hosts. By not setting a host key policy for unknown hosts, `paramiko`'s default policy is to use `RejectPolicy`. Example configuration connecting to a known, trusted host, and not allowing connections to unknown hosts: ``` import paramiko # Create an SSH client with paramiko.SSHClient() as ssh: # Load the system host keys so we can confirm the # host we are connecting to is legitimate ssh.load_system_host_keys('/home/appuser/.ssh/known_hosts') # Connect to the remote host using our SSH private key ssh.connect(hostname='example.org', port=22, username='appuser', key_filename='/home/appuser/.ssh/private_key') ``` For more information on `set_missing_host_key_policy` see: - https://docs.paramiko.org/en/stable/api/client.html#paramiko.client.SSHClient.set_missing_host_key_policy

No author info

The application was found using the `xml.etree` package for processing XML. Pythons default xml processors suffer from various XML parsing vulnerabilities and care must be taken when handling XML data. Additionally, depending on the version of Python, more critical vulnerabilities such as eXternal XML Entity injection maybe exploitable. The `etree` package suffers from the following security risks as of Python 3.7.1: * Billion laughs / exponential entity expansion - May allow an adversary to cause a Denial of Service (DoS) against the application parsing arbitrary XML. * Quadratic blowup entity expansion - Similar to above, but requires a larger input to cause the Denial of Service. To remediate the above issues, consider using the [defusedxml](https://pypi.org/project/defusedxml/) library when processing untrusted XML. Example parsing an XML document using defusedxml: ``` from defusedxml.ElementTree import parse # Parse the inventory.xml file et = parse('inventory.xml') # Get the root element root = et.getroot() # Work with the root element # ... ``` For more information on the various XML parsers and their vulnerabilities please see: - https://docs.python.org/3/library/xml.html#xml-vulnerabilities For more information on XML security see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#python

No author info

The application was found using the `xml.etree` package for processing XML. Pythons default xml processors suffer from various XML parsing vulnerabilities and care must be taken when handling XML data. Additionally, depending on the version of Python, more critical vulnerabilities such as eXternal XML Entity injection maybe exploitable. The `etree` package suffers from the following security risks as of Python 3.7.1: * Billion laughs / exponential entity expansion - May allow an adversary to cause a Denial of Service (DoS) against the application parsing arbitrary XML. * Quadratic blowup entity expansion - Similar to above, but requires a larger input to cause the Denial of Service. To remediate the above issues, consider using the [defusedxml](https://pypi.org/project/defusedxml/) library when processing untrusted XML. Example parsing an XML document using defusedxml: ``` from defusedxml.ElementTree import parse # Parse the inventory.xml file et = parse('inventory.xml') # Get the root element root = et.getroot() # Work with the root element # ... ``` For more information on the various XML parsers and their vulnerabilities please see: - https://docs.python.org/3/library/xml.html#xml-vulnerabilities For more information on XML security see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#python

No author info

The application was found using the `lxml.etree` package for processing XML. Python's default XML processors suffer from various XML parsing vulnerabilities and care must be taken when handling XML data. Additionally, depending on the version of Python, more critical vulnerabilities such as eXternal XML Entity injection maybe exploitable. The `etree` package suffers from the following security risks as of Python 3.7.1: * Billion laughs / exponential entity expansion - May allow an adversary to cause a Denial of Service (DoS) against the application parsing arbitrary XML. * Quadratic blowup entity expansion - Similar to above, but requires a larger input to cause the Denial of Service. To remediate the above issues, consider using the [defusedxml](https://pypi.org/project/defusedxml/) library when processing untrusted XML. Example parsing an XML document using defusedxml: ``` from defusedxml.ElementTree import parse # Parse the inventory.xml file et = parse('inventory.xml') # Get the root element root = et.getroot() # Work with the root element # ... ``` For more information on the various XML parsers and their vulnerabilities please see: - https://docs.python.org/3/library/xml.html#xml-vulnerabilities For more information on XML security see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#python

No author info

The application was found using the `xml.dom.expatbuilder` which calls the `xml.dom.minidom` package for processing XML. Python's default XML processors suffer from various XML parsing vulnerabilities and care must be taken when handling XML data. Additionally, depending on the version of Python, more critical vulnerabilities such as eXternal XML Entity injection maybe exploitable. The `xml.dom.minidom` package suffers from the following security risks as of Python 3.7.1: * Billion laughs / exponential entity expansion - May allow an adversary to cause a Denial of Service (DoS) against the application parsing arbitrary XML. * Quadratic blowup entity expansion - Similar to above, but requires a larger input to cause the Denial of Service. To remediate the above issues, consider using the [defusedxml](https://pypi.org/project/defusedxml/) library when processing untrusted XML. Example parsing an XML document using defusedxml: ``` from defusedxml.ElementTree import parse # Parse the inventory.xml file et = parse('inventory.xml') # Get the root element root = et.getroot() # Work with the root element # ... ``` For more information on the various XML parsers and their vulnerabilities please see: - https://docs.python.org/3/library/xml.html#xml-vulnerabilities For more information on XML security see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#python

No author info

The application was found using the `xml.sax.expatreader` package for processing XML. Python's default XML processors suffer from various XML parsing vulnerabilities and care must be taken when handling XML data. Additionally, depending on the version of Python, more critical vulnerabilities such as eXternal XML Entity injection maybe exploitable. The `xml.sax` package suffers from the following security risks as of Python 3.7.1: * Billion laughs / exponential entity expansion - May allow an adversary to cause a Denial of Service (DoS) against the application parsing arbitrary XML. * Quadratic blowup entity expansion - Similar to above, but requires a larger input to cause the Denial of Service. To remediate the above issues, consider using the [defusedxml](https://pypi.org/project/defusedxml/) library when processing untrusted XML. Example parsing an XML document using defusedxml: ``` from defusedxml.ElementTree import parse # Parse the inventory.xml file et = parse('inventory.xml') # Get the root element root = et.getroot() # Work with the root element # ... ``` For more information on the various XML parsers and their vulnerabilities please see: - https://docs.python.org/3/library/xml.html#xml-vulnerabilities For more information on XML security see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#python

No author info

The application was found using the `xml.dom.minidom` package for processing XML. Python's default XML processors suffer from various XML parsing vulnerabilities and care must be taken when handling XML data. Additionally, depending on the version of Python, more critical vulnerabilities such as eXternal XML Entity injection maybe exploitable. The `xml.dom.minidom` package suffers from the following security risks as of Python 3.7.1: * Billion laughs / exponential entity expansion - May allow an adversary to cause a Denial of Service (DoS) against the application parsing arbitrary XML. * Quadratic blowup entity expansion - Similar to above, but requires a larger input to cause the Denial of Service. To remediate the above issues, consider using the [defusedxml](https://pypi.org/project/defusedxml/) library when processing untrusted XML. Example parsing an XML document using defusedxml: ``` from defusedxml.ElementTree import parse # Parse the inventory.xml file et = parse('inventory.xml') # Get the root element root = et.getroot() # Work with the root element # ... ``` For more information on the various XML parsers and their vulnerabilities please see: - https://docs.python.org/3/library/xml.html#xml-vulnerabilities For more information on XML security see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#python

No author info

The application was found using the `xml.dom.pulldom` package for processing XML. Python's default XML processors suffer from various XML parsing vulnerabilities and care must be taken when handling XML data. Additionally, depending on the version of Python, more critical vulnerabilities such as eXternal XML Entity injection maybe exploitable. The `xml.dom.pulldom` package suffers from the following security risks as of Python 3.7.1: * Billion laughs / exponential entity expansion - May allow an adversary to cause a Denial of Service (DoS) against the application parsing arbitrary XML. * Quadratic blowup entity expansion - Similar to above, but requires a larger input to cause the Denial of Service. To remediate the above issues, consider using the [defusedxml](https://pypi.org/project/defusedxml/) library when processing untrusted XML. Example parsing an XML document using defusedxml: ``` from defusedxml.ElementTree import parse # Parse the inventory.xml file et = parse('inventory.xml') # Get the root element root = et.getroot() # Work with the root element # ... ``` For more information on the various XML parsers and their vulnerabilities please see: - https://docs.python.org/3/library/xml.html#xml-vulnerabilities For more information on XML security see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#python

No author info

The application was found using the `xml.sax` package for processing XML. Python's default XML processors suffer from various XML parsing vulnerabilities and care must be taken when handling XML data. Additionally, depending on the version of Python, more critical vulnerabilities such as eXternal XML Entity injection maybe exploitable. The `xml.sax` package suffers from the following security risks as of Python 3.7.1: * Billion laughs / exponential entity expansion - May allow an adversary to cause a Denial of Service (DoS) against the application parsing arbitrary XML. * Quadratic blowup entity expansion - Similar to above, but requires a larger input to cause the Denial of Service. To remediate the above issues, consider using the [defusedxml](https://pypi.org/project/defusedxml/) library when processing untrusted XML. Example parsing an XML document using defusedxml: ``` from defusedxml.ElementTree import parse # Parse the inventory.xml file et = parse('inventory.xml') # Get the root element root = et.getroot() # Work with the root element # ... ``` For more information on the various XML parsers and their vulnerabilities please see: - https://docs.python.org/3/library/xml.html#xml-vulnerabilities For more information on XML security see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#python

profile photo of returntocorpreturntocorp

Unsafe usage of mutable initializer with attr.s decorator. Multiple instances of this class will re-use the same data structure, which is likely not the desired behavior. Consider instead: replace assignment to mutable initializer (ex. dict() or {}) with attr.ib(factory=type) where type is dict, set, or list

profile photo of returntocorpreturntocorp

Avoid using null on string-based fields such as CharField and TextField. If a string-based field has null=True, that means it has two possible values for "no data": NULL, and the empty string. In most cases, it's redundant to have two possible values for "no data;" the Django convention is to use the empty string, not NULL.

profile photo of returntocorpreturntocorp

Hardcoded JWT secret or private key is used. This is a Insufficiently Protected Credentials weakness: https://cwe.mitre.org/data/definitions/522.html Consider using an appropriate security mechanism to protect the credentials (e.g. keeping secrets in environment variables)

profile photo of returntocorpreturntocorp

Avoid using `shelve`, which uses `pickle`, which is known to lead to code execution vulnerabilities. When unpickling, the serialized data could be manipulated to run arbitrary code. Instead, consider serializing the relevant data as JSON or a similar text-based serialization format.

profile photo of returntocorpreturntocorp

Detected string concatenation or formatting in a call to a command via 'sh'. This could be a command injection vulnerability if the data is user-controlled. Instead, use a list and append the argument.

profile photo of returntocorpreturntocorp

Distinct, Having, Group_by, Order_by, and Filter in SQLAlchemy can cause sql injections if the developer inputs raw SQL into the before-mentioned clauses. This pattern captures relevant cases in which the developer inputs raw SQL into the distinct, having, group_by, order_by or filter clauses and injects user-input into the raw SQL with any function besides "bindparams". Use bindParams to securely bind user-input to SQL statements.

profile photo of returntocorpreturntocorp

Detected a 'requests' call without a timeout set. By default, 'requests' calls wait until the connection is closed. This means a 'requests' call without a timeout will hang the program if a response is never received. Consider setting a timeout for all 'requests'.

profile photo of returntocorpreturntocorp

Found a class extending 'SafeString', 'SafeText' or 'SafeData'. These classes are for bypassing the escaping engine built in to Django and should not be used directly. Improper use of this class exposes your application to cross-site scripting (XSS) vulnerabilities. If you need this functionality, use 'mark_safe' instead and ensure no user data can reach it.

profile photo of returntocorpreturntocorp

Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition, use SQL Expression Language or Schema Definition Language. In most cases, SQLAlchemy ORM will be a better option.

profile photo of returntocorpreturntocorp

Function $F mutates default list $D. Python only instantiates default function arguments once and shares the instance across the function calls. If the default function argument is mutated, that will modify the instance used by all future function calls. This can cause unexpected results, or lead to security vulnerabilities whereby one function consumer can view or modify the data of another function consumer. Instead, use a default argument (like None) to indicate that no argument was provided and instantiate a new list at that time. For example: `if $D is None: $D = []`.

profile photo of returntocorpreturntocorp

Detected a possible YAML deserialization vulnerability. `yaml.unsafe_load`, `yaml.Loader`, `yaml.CLoader`, and `yaml.UnsafeLoader` are all known to be unsafe methods of deserializing YAML. An attacker with control over the YAML input could create special YAML input that allows the attacker to run arbitrary Python code. This would allow the attacker to steal files, download and install malware, or otherwise take over the machine. Use `yaml.safe_load` or `yaml.SafeLoader` instead.

profile photo of returntocorpreturntocorp

Avoid using `dill`, which uses `pickle`, which is known to lead to code execution vulnerabilities. When unpickling, the serialized data could be manipulated to run arbitrary code. Instead, consider serializing the relevant data as JSON or a similar text-based serialization format.

profile photo of returntocorpreturntocorp

The Python documentation recommends using `defusedxml` instead of `xml` because the native Python `xml` library is vulnerable to XML External Entity (XXE) attacks. These attacks can leak confidential data and "XML bombs" can cause denial of service.

profile photo of returntocorpreturntocorp

Detected user input used to manually construct a SQL string. This is usually bad practice because manual construction could accidentally result in a SQL injection. An attacker could use a SQL injection to steal or modify contents of the database. Instead, use a parameterized query which is available by default in most database engines. Alternatively, consider using an object-relational mapper (ORM) such as Sequelize which will protect your queries.

profile photo of returntocorpreturntocorp

Detected `os` function with argument tainted by `event` object. This is dangerous if external data can reach this function call because it allows a malicious actor to execute commands. Use the 'subprocess' module instead, which is easier to use without accidentally exposing a command injection vulnerability.

profile photo of returntocorpreturntocorp

Detected use of the wildcard character in a system call that spawns a shell. This subjects the wildcard to normal shell expansion, which can have unintended consequences if there exist any non-standard file names. Consider a file named '-e sh script.sh' -- this will execute a script when 'rsync' is called. See https://www.defensecode.com/public/DefenseCode_Unix_WildCards_Gone_Wild.txt for more information.

profile photo of returntocorpreturntocorp

Data from request object is passed to a new server-side request. This could lead to a server-side request forgery (SSRF). To mitigate, ensure that schemes and hosts are validated against an allowlist, do not forward the response to the user, and ensure proper authentication and transport-layer security in the proxied request.

profile photo of returntocorpreturntocorp

Be careful with `flask.make_response()`. If this response is rendered onto a webpage, this could create a cross-site scripting (XSS) vulnerability. `flask.make_response()` will not autoescape HTML. If you are rendering HTML, write your HTML in a template file and use `flask.render_template()` which will take care of escaping. If you are returning data from an API, consider using `flask.jsonify()`.

No author info

The application was found using `dill` which is vulnerable to deserialization attacks. Deserialization attacks exploit the process of reading serialized data and turning it back into an object. By constructing malicious objects and serializing them, an adversary may attempt to: - Inject code that is executed upon object construction, which occurs during the deserialization process. - Exploit mass assignment by including fields that are not normally a part of the serialized data but are read in during deserialization. Consider safer alternatives such as serializing data in the JSON format. Ensure any format chosen allows the application to specify exactly which object types are allowed to be deserialized. To protect against mass assignment, only allow deserialization of the specific fields that are required. If this is not easily done, consider creating an intermediary type that can be serialized with only the necessary fields exposed. Example JSON deserializer using an intermediary type that is validated against a schema to ensure it is safe from mass assignment: ``` import jsonschema # Create a schema to validate our user-supplied input against # an intermediary object intermediary_schema = { "type" : "object", "properties" : { "name": {"type" : "string"} }, "required": ["name"], # Protect against random properties being added to the object "additionalProperties": False, } # If a user attempted to add "'is_admin': True" it would cause a validation error intermediary_object = {'name': 'test user'} try: # Validate the user supplied intermediary object against our schema jsonschema.validate(instance=intermediary_object, schema=intermediary_schema) user_object = {'user': { # Assign the deserialized data from intermediary object 'name': intermediary_object['name'], # Add in protected data in object definition (or set it from a class constructor) 'is_admin': False, } } # Work with the user_object except jsonschema.exceptions.ValidationError as ex: # Gracefully handle validation errors # ... ``` For more details on deserialization attacks in general, see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html

profile photo of returntocorpreturntocorp

This expression will evaluate to be ONLY value the of the `else` clause if the condition `$EXPRESSION` is false. If you meant to do list concatenation, put parentheses around the entire concatenation expression, like this: `['a', 'b', 'c'] + (['d'] if x else ['e'])`. If this is the intended behavior, the expression may be confusing to others, and you may wish to add parentheses for readability.

profile photo of returntocorpreturntocorp

Detected a Jinja2 environment with 'autoescaping' disabled. This is dangerous if you are rendering to a browser because this allows for cross-site scripting (XSS) attacks. If you are in a web context, enable 'autoescaping' by setting 'autoescape=True.' You may also consider using 'jinja2.select_autoescape()' to only enable automatic escaping for certain file extensions.

profile photo of returntocorpreturntocorp

Detected a Jinja2 environment without autoescaping. Jinja2 does not autoescape by default. This is dangerous if you are rendering to a browser because this allows for cross-site scripting (XSS) attacks. If you are in a web context, enable autoescaping by setting 'autoescape=True.' You may also consider using 'jinja2.select_autoescape()' to only enable automatic escaping for certain file extensions.

profile photo of returntocorpreturntocorp

Socket is not closed if shutdown fails. When socket.shutdown fails on an OSError, socket.close is not called and the code fails to clean up the socket and allow garbage collection to release the memory used for it. The OSError on shutdown can occur when the remote side of the connection closes the connection first.

profile photo of returntocorpreturntocorp

A hard-coded credential was detected. It is not recommended to store credentials in source-code, as this risks secrets being leaked and used by either an internal or external malicious adversary. It is recommended to use environment variables to securely provide credentials or retrieve credentials from a secure vault or HSM (Hardware Security Module).

profile photo of returntocorpreturntocorp

Detected usage of @csrf_exempt, which indicates that there is no CSRF token set for this route. This could lead to an attacker manipulating the user's account and exfiltration of private data. Instead, create a function without this decorator.

profile photo of returntocorpreturntocorp

`html_safe()` add the `__html__` magic method to the provided class. The `__html__` method indicates to the Django template engine that the value is 'safe' for rendering. This means that normal HTML escaping will not be applied to the return value. This exposes your application to cross-site scripting (XSS) vulnerabilities. If you need to render raw HTML, consider instead using `mark_safe()` which more clearly marks the intent to render raw HTML than a class with a magic method.

profile photo of returntocorpreturntocorp

Found user data in a call to 'eval'. This is extremely dangerous because it can enable an attacker to execute arbitrary remote code on the system. Instead, refactor your code to not use 'eval' and instead use a safe library for the specific functionality you need.

profile photo of returntocorpreturntocorp

Data from request object is passed to a new server-side request. This could lead to a server-side request forgery (SSRF), which could result in attackers gaining access to private organization data. To mitigate, ensure that schemes and hosts are validated against an allowlist, do not forward the response to the user, and ensure proper authentication and transport-layer security in the proxied request.

profile photo of returntocorpreturntocorp

Detected Flask app with debug=True. Do not deploy to production with this flag enabled as it will leak sensitive information. Instead, consider using Flask configuration variables or setting 'debug' using system environment variables.

profile photo of returntocorpreturntocorp

Function $F mutates default dict $D. Python only instantiates default function arguments once and shares the instance across the function calls. If the default function argument is mutated, that will modify the instance used by all future function calls. This can cause unexpected results, or lead to security vulnerabilities whereby one function consumer can view or modify the data of another function consumer. Instead, use a default argument (like None) to indicate that no argument was provided and instantiate a new dictionary at that time. For example: `if $D is None: $D = {}`.

profile photo of returntocorpreturntocorp

The Connection.recv() method automatically unpickles the data it receives, which can be a security risk unless you can trust the process which sent the message. Therefore, unless the connection object was produced using Pipe() you should only use the recv() and send() methods after performing some sort of authentication. See more dettails: https://docs.python.org/3/library/multiprocessing.html?highlight=security#multiprocessing.connection.Connection

profile photo of returntocorpreturntocorp

Avoid using `pickle`, which is known to lead to code execution vulnerabilities. When unpickling, the serialized data could be manipulated to run arbitrary code. Instead, consider serializing the relevant data as JSON or a similar text-based serialization format.

profile photo of returntocorpreturntocorp

Avoid using `cPickle`, which is known to lead to code execution vulnerabilities. When unpickling, the serialized data could be manipulated to run arbitrary code. Instead, consider serializing the relevant data as JSON or a similar text-based serialization format.

profile photo of returntocorpreturntocorp

Detected string concatenation with a non-literal variable in an aiopg Python SQL statement. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries instead. You can create parameterized queries like so: 'cur.execute("SELECT %s FROM table", (user_value,))'.

profile photo of returntocorpreturntocorp

Detected string concatenation with a non-literal variable in a asyncpg Python SQL statement. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can create parameterized queries like so: 'conn.fetch("SELECT $1 FROM table", value)'. You can also create prepared statements with 'Connection.prepare': 'stmt = conn.prepare("SELECT $1 FROM table"); await stmt.fetch(user_value)'

No author info

The application was found using `assert` in non-test code. Usually reserved for debug and test code, the `assert` function is commonly used to test conditions before continuing execution. However, enclosed code will be removed when compiling Python code to optimized byte code. Depending on the assertion and subsequent logic, this could lead to undefined behavior of the application or application crashes. To remediate this issue, remove the `assert` calls. If necessary, replace them with either `if` conditions or `try/except` blocks. Example using `try/except` instead of `assert`: ``` # Below try/except is equal to the assert statement of: # assert user.is_authenticated(), "user must be authenticated" try: if not user.is_authenticated(): raise AuthError("user must be authenticated") except AuthError as e: # Handle error # ... # Return, do not continue processing return ```

No author info

Binding to all network interfaces can potentially open up a service to traffic on unintended interfaces, that may not be properly documented or secured. By passing "0.0.0.0", "::" or an empty string as the address to the `socket.bind` function, the application will bind to all interfaces. Consider passing in the interface ip address through an environment variable, configuration file, or by determining the primary interface(s) IP address. Example getting the IP address from an environment variable `IP_ADDRESS`: ``` # Get the IP_ADDRESS env variable, or bind to # 127.0.0.1 if it is not set address = os.getenv("IP_ADDRESS", "127.0.0.1") # Create an internet socket sock = socket.socket(socket.AF_INET) # Set the port to listen on port = 9777 # Bind to the address and port combination sock.bind((address, port)) # Listen for connections sock.listen() # Handle the connection ```

No author info

The application was found calling the `exec` function with a non-literal variable. If the variable comes from user-supplied input, an adversary could compromise the entire system by executing arbitrary python code. To remediate this issue, remove all calls to `exec` and consider alternative methods for executing the necessary business logic. There is almost no safe method of calling `eval` with user-supplied input. If the application only needs to convert strings into objects, consider using `json.loads`. In some cases `ast.literal_eval` is recommended, but this should be avoided as it can still suffer from other issues such as the ability for malicious code to crash the python interpreter or application. Example using `json.loads`` to load in arbitrary data to create data structures: ``` # User supplied data as a blob of JSON user_supplied_data = """{"user": "test", "metadata": [1,2,3]}""" # Load the JSON user_object = json.loads(user_supplied_data) # Manually add protected properties _after_ loading, never before user_object["is_admin"] = False # Work with the object ```

No author info

The application was found setting file permissions to overly permissive values. Consider using the following values if the application user is the only process to access the file: - 0400 - read only access to the file - 0200 - write only access to the file - 0600 - read/write access to the file Example creating a file with read/write permissions for the application user: ``` # Use octal values to set 0o600 (read/write access to the file) for the current # user os.chmod('somefile.txt', 0o600) ``` For all other values please see: https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation

No author info

The application was found using `shelve` which is vulnerable to deserialization attacks as it calls `pickle` internally. Deserialization attacks exploit the process of reading serialized data and turning it back into an object. By constructing malicious objects and serializing them, an adversary may attempt to: - Inject code that is executed upon object construction, which occurs during the deserialization process. - Exploit mass assignment by including fields that are not normally a part of the serialized data but are read in during deserialization. Consider safer alternatives such as serializing data in the JSON format. Ensure any format chosen allows the application to specify exactly which object types are allowed to be deserialized. To protect against mass assignment, only allow deserialization of the specific fields that are required. If this is not easily done, consider creating an intermediary type that can be serialized with only the necessary fields exposed. Example JSON deserializer using an intermediary type that is validated against a schema to ensure it is safe from mass assignment: ``` import jsonschema # Create a schema to validate our user-supplied input against # an intermediary object intermediary_schema = { "type" : "object", "properties" : { "name": {"type" : "string"} }, "required": ["name"], # Protect against random properties being added to the object "additionalProperties": False, } # If a user attempted to add "'is_admin': True" it would cause a validation error intermediary_object = {'name': 'test user'} try: # Validate the user supplied intermediary object against our schema jsonschema.validate(instance=intermediary_object, schema=intermediary_schema) user_object = {'user': { # Assign the deserialized data from intermediary object 'name': intermediary_object['name'], # Add in protected data in object definition (or set it from a class constructor) 'is_admin': False, } } # Work with the user_object except jsonschema.exceptions.ValidationError as ex: # Gracefully handle validation errors # ... ``` For more details on deserialization attacks in general, see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html

No author info

Detected MD2 hash algorithm which is considered insecure. This algorithm has many known vulnerabilities and has been deprecated. Use SHA256 or SHA3 instead.

No author info

Detected MD4 hash algorithm which is considered insecure. This algorithm has many known vulnerabilities and has been deprecated. Use SHA256 or SHA3 instead.

No author info

Detected MD5 hash algorithm which is considered insecure. MD5 is not collision resistant and is therefore not suitable as a cryptographic signature. Use SHA256 or SHA3 instead.

No author info

The application was found creating temporary files with the insecure `mktemp` method. Depending on how the application uses this temporary file, an attacker may be able to create symlinks that point to other files prior to the application creating or writing to the target file, leading to unintended files being created or overwritten. To remediate this issue consider using `tempfile.TemporaryFile` instead. Example using `tempfile.TemporaryFile` to write a file: ``` import tempfile # Open a new temporary file using a context manager with tempfile.TemporaryFile() as fp: # Write some data to the temporary file fp.write(b'Some data') # Seek back to beginning of file fp.seek(0) # Read it data = fp.read() # File is automatically closed/removed once we exit the with context ``` For more information on alternative tempfile functions see: - https://docs.python.org/3/library/tempfile.html

No author info

The application was found using an insecure or risky digest or signature algorithm. MD2, MD4, MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. It is strongly recommended that a standard digest algorithm be chosen instead as implementing a custom algorithm is prone to errors. Example using `hashlib.sha384()` to create a SHA384 hash: ``` import hashlib # Create a SHA384 digest digest = hashlib.sha384() # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes digest.digest() ```

No author info

The application was found using a telnet library. As telnet does not provide encryption, it is strongly recommended that communications use a more secure transport such as SSH. The [paramiko](https://www.paramiko.org/) library can be used to initiate SSH connections. Example using `paramiko` SSH client: ``` import paramiko import scp # Create an SSH client with paramiko.SSHClient() as ssh: # Load the system host keys so we can confirm the # host we are connecting to is legitimate ssh.load_system_host_keys('/home/appuser/.ssh/known_hosts') # Connect to the remote host using our SSH private key ssh.connect(hostname='example.org', port=22, username='appuser', key_filename='/home/appuser/.ssh/private_key') # Work with the connection ``` For more information on the paramiko module see: - https://www.paramiko.org/

No author info

The application was found using the `requests` module without configuring a timeout value for connections. The `verify=False` argument has been set, which effectively disables the validation of server certificates. This allows for an adversary who is in between the application and the target host to intercept potentially sensitive information or transmit malicious data. To remediate this issue either remove the `verify=False` argument, or set `verify=True`to each `requests` call. Example verifying server certificates for an HTTP GET request: ``` # Issue a GET request to https://example.com with a timeout of 10 seconds and verify the # server certificate explicitly. response = requests.get('https://example.com', timeout=10, verify=True) # Work with the response object # ... ``` For more information on using the requests module see: - https://requests.readthedocs.io/en/latest/api/

No author info

An insecure SSL version was detected. TLS versions 1.0, 1.1, and all SSL versions are considered weak encryption and are deprecated. Use 'ssl.PROTOCOL_TLSv1_2' or higher.

No author info

The application was found calling `ssl.wrap_socket` without a TLS protocol version specified. Additionally, `ssl.wrap_socket` has been deprecated since Python 3.7. It is strongly recommended that newer applications use TLS 1.2 or 1.3 and `SSLContext.wrap_socket`. To remediate this issue, create a new TLS context and pass in `ssl.PROTOCOL_TLS_CLIENT` for clients or `ssl.PROTOCOL_TLS_SERVER` for servers to the `ssl.SSLContext(...)` `protocol=` argument. When converting the socket to a TLS socket, use the new `SSLContext.wrap_socket` method instead. Example creating a TLS 1.3 client socket connection by using a newer version of Python (3.11.4) and the SSL module: ``` import ssl import socket # Create our initial socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: # Connect the socket sock.connect(('www.example.org', 443)) # Create a new SSLContext with protocol set to ssl.PROTOCOL_TLS_CLIENT # This will auto-select the highest grade TLS protocol version (1.3) context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT) # Load our a certificates for server certificate authentication context.load_verify_locations('cert.pem') # Create our TLS socket, and validate the server hostname matches with context.wrap_socket(sock, server_hostname="www.example.org") as tls_sock: # Send some bytes over the socket (HTTP request in this case)\ data = bytes('GET / HTTP/1.1\r\nHost: example.org\r\n\r\n', 'utf-8') sent_bytes = tls_sock.send(data) # Validate number of sent bytes # ... # Read the response resp = tls_sock.recv() # Work with the response # ... ``` For more information on the ssl module see: - https://docs.python.org/3/library/ssl.html

No author info

`mark_safe()` is used to mark a string as `safe` for HTML output. This disables escaping and could therefore subject the content to XSS attacks. Use `django.utils.html.format_html()` to build HTML for rendering instead.

No author info

The application was found using Jinja2 `Environment` without autoescaping enabled. If using in the context of HTML this could lead to Cross-Site Scripting (XSS) attacks when rendering with user-supplied input. Unfortunately, Jinja2 does not support context-aware escaping, meaning it is insufficient to protect against XSS for the various web contexts. It is important to encode the data depending on the specific context it is used in. There are at least six context types: - Inside HTML tags `<div>context 1</div>` - Inside attributes: `<div class="context 2"></div>` - Inside event attributes `<button onclick="context 3">button</button>` - Inside script blocks: `<script>var x = "context 4"</script>` - Unsafe element HTML assignment: `element.innerHTML = "context 5"` - Inside URLs: `<iframe src="context 6"></iframe><a href="context 6">link</a>` Script blocks alone have multiple ways they need to be encoded. Extra care must be taken if user input is ever output inside of script tags. User input that is displayed within the application must be encoded, sanitized or validated to ensure it cannot be treated as HTML or executed as Javascript code. Care must also be taken to not mix server-side templating with client-side templating, as the server-side templating will not encode things like {{ 7*7 }} which may execute client-side templating features. It is _NOT_ advised to encode user input prior to inserting into a data store. The data will need to be encoded depending on context of where it is output. It is much safer to force the displaying system to handle the encoding and not attempt to guess how it should be encoded. To handle different contexts, one approach would be to write custom Jinja2 filters. Below is an example that escapes or encodes links and potentially malicious script, note this does not include other contexts such as CSS or attributes: ``` from jinja2 import Environment, select_autoescape, FileSystemLoader from jinja2 import pass_eval_context from markupsafe import Markup, escape @pass_eval_context def escape_link(eval_ctx, value): bad_link = "#JinjatmplZ" # Block any values that start with // as that could be used to inject # links to third party pages see: https://en.wikipedia.org/wiki/Wikipedia:Protocol-relative_URL if value.startswith('//'): return bad_link # Only allow relative links # if you want to allow links that start with http or ws replace with below: # if not value.startswith('/'): and not value.startswith('http') and not value.startswith('ws') if not value.startswith('/'): return bad_link # Alternatively, you could only call escape if autoescape is true # if eval_ctx.autoescape: # return escape(value) # else # return value return escape(value) # Create a replacement table js_replacement = str.maketrans({ '\0': "\\u0000", '\t': "\\t", '\n': "\\n", '\v': "\\u000b", '\f': "\\f`", '\r': "\\r", '"': "\\u0022", '`': "\\u0060", '&': "\\u0026", '\'': "\\u0027", '+': "\\u002b", '/': "\\/", '<': "\\u003c", '>': "\\u003e", '\\': "\\\\", '(': "\\u0028", ')': "\\u0029", }) @pass_eval_context def escape_js(eval_ctx, value): """ Escape the input for use in <script> context, USE WITH CAUTION It is strongly recommended to _never_ pass user-supplied input to the JavaScript context. This may still be unsafe depending where used, it does not consider characters used in regular expressions for example. """ #if eval_ctx.autoescape: # value = escape(value) # Escape by default value = escape(value) # Translate any potential characters using our translation table return value.translate(js_replacement) # Create our environment, setting autoescape to use the default # select_autoescape function env = Environment( loader=FileSystemLoader(os.getcwd()+"/template"), autoescape=select_autoescape, ) # Add an escape link filter to be used in our template env.filters["escape_link"] = escape_link env.filters["escape_js"] = escape_js # Load our template file template = env.get_template("mytemplate.html") # Render with different variables which call our filters print(template.render( html_context="<img src=x onerror=alert(1)>", link_context="/# onclick=alert(1)<script>alert(1)</script>", script_context="alert(1);alert`1`",) ) # Sample template: """ <!DOCTYPE html> <html lang="en"> <head> <title>My Webpage</title> </head> <body> <h1>My Webpage</h1> {{ html_context }} <a href="{{ link_context | escape_link }}">link</a> <script>{{ script_context | escape_js }}</script> </body> </html> """ ``` For more information on autoescape see: - https://jinja.palletsprojects.com/en/3.1.x/api/#autoescaping For more information on XSS see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html

No author info

The application was found using an insecure or risky digest or signature algorithm. MD2, MD4, MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. Note that the `Crypto` and `Cryptodome` Python packages are no longer recommended for new applications, instead consider using the [cryptography](https://cryptography.io/) package. Example of creating a SHA-384 hash using the `cryptography` package: ``` from cryptography.hazmat.primitives import hashes # Create a SHA384 digest digest = hashes.Hash(hashes.SHA384()) # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes result = digest.finalize() ``` For more information on secure password storage see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was found using `pickle` which is vulnerable to deserialization attacks. Deserialization attacks exploit the process of reading serialized data and turning it back into an object. By constructing malicious objects and serializing them, an adversary may attempt to: - Inject code that is executed upon object construction, which occurs during the deserialization process. - Exploit mass assignment by including fields that are not normally a part of the serialized data but are read in during deserialization. Consider safer alternatives such as serializing data in the JSON format. Ensure any format chosen allows the application to specify exactly which object types are allowed to be deserialized. To protect against mass assignment, only allow deserialization of the specific fields that are required. If this is not easily done, consider creating an intermediary type that can be serialized with only the necessary fields exposed. Example JSON deserializer using an intermediary type that is validated against a schema to ensure it is safe from mass assignment: ``` import jsonschema # Create a schema to validate our user-supplied input against # an intermediary object intermediary_schema = { "type" : "object", "properties" : { "name": {"type" : "string"} }, "required": ["name"], # Protect against random properties being added to the object "additionalProperties": False, } # If a user attempted to add "'is_admin': True" it would cause a validation error intermediary_object = {'name': 'test user'} try: # Validate the user supplied intermediary object against our schema jsonschema.validate(instance=intermediary_object, schema=intermediary_schema) user_object = {'user': { # Assign the deserialized data from intermediary object 'name': intermediary_object['name'], # Add in protected data in object definition (or set it from a class constructor) 'is_admin': False, } } # Work with the user_object except jsonschema.exceptions.ValidationError as ex: # Gracefully handle validation errors # ... ``` For more details on deserialization attacks in general, see OWASP's guide: - https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html

No author info

The Flask application is running with `debug=True` configured. By enabling this option, certain exceptions or errors could cause sensitive information to be leaked in HTTP responses. Additionally, it is not recommended to run a Flask application using `Flask.run(...)` in production. Instead, a WSGI server such as [gunicorn](https://flask.palletsprojects.com/en/2.3.x/deploying/gunicorn/) or [waitress](https://flask.palletsprojects.com/en/2.3.x/deploying/waitress/) be used instead. For more information on deployment options for Flask applications see: - https://flask.palletsprojects.com/en/2.3.x/deploying/

No author info

The application was found using an insecure or risky digest or signature algorithm. MD2, MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. It is strongly recommended that a standard digest algorithm be chosen instead as implementing a custom algorithm is prone to errors. Example of creating a SHA-384 hash using the `cryptography` package: ``` from cryptography.hazmat.primitives import hashes # Create a SHA384 digest digest = hashes.Hash(hashes.SHA384()) # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes result = digest.finalize() ``` For more information on secure password storage see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was found using an insecure or risky digest or signature algorithm. MD2, MD5 and SHA1 hash algorithms have been found to be vulnerable to producing collisions. This means that two different values, when hashed, can lead to the same hash value. If the application is trying to use these hash methods for storing passwords, then it is recommended to switch to a password hashing algorithm such as Argon2id or PBKDF2. It is strongly recommended that a standard digest algorithm be chosen instead as implementing a custom algorithm is prone to error. Example of creating a SHA-384 hash using the `cryptography` package: ``` from cryptography.hazmat.primitives import hashes # Create a SHA384 digest digest = hashes.Hash(hashes.SHA384()) # Update the digest with some initial data digest.update(b"some data to hash") # Add more data to the digest digest.update(b"some more data") # Finalize the digest as bytes result = digest.finalize() ``` For more information on secure password storage see OWASP: - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html For more information on the cryptography module see: - https://cryptography.io/en/latest/

profile photo of returntocorpreturntocorp

Using 'globals()' as a context to 'render(...)' is extremely dangerous. This exposes Python functions to the template that were not meant to be exposed. An attacker could use these functions to execute code that was not intended to run and could compromise the application. (This is server-side template injection (SSTI)). Do not use 'globals()'. Instead, specify each variable in a dictionary or 'django.template.Context' object, like '{"var1": "hello"}' and use that instead.

profile photo of returntocorpreturntocorp

Using 'locals()' as a context to 'render(...)' is extremely dangerous. This exposes Python functions to the template that were not meant to be exposed. An attacker could use these functions to execute code that was not intended to run and could compromise the application. (This is server-side template injection (SSTI)). Do not use 'locals()'. Instead, specify each variable in a dictionary or 'django.template.Context' object, like '{"var1": "hello"}' and use that instead.

No author info

Cryptographic algorithms provide many different modes of operation, only some of which provide message integrity. Without message integrity it could be possible for an adversary to attempt to tamper with the ciphertext which could lead to compromising the encryption key. Newer algorithms apply message integrity to validate ciphertext has not been tampered with. Instead of using an algorithm that requires configuring a cipher mode, an algorithm that has built-in message integrity should be used. Consider using `ChaCha20Poly1305` or `AES-256-GCM` instead. For older applications that don't have support for `ChaCha20Poly1305`, `AES-256-GCM` is recommended, however it has many drawbacks: - Slower than `ChaCha20Poly1305`. - Catastrophic failure if nonce values are reused. Example using `ChaCha20Poly1305`: ``` import os # Import ChaCha20Poly1305 from cryptography from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = ChaCha20Poly1305.generate_key() # Create a new ChaCha20Poly1305 instance with our secure key chacha = ChaCha20Poly1305(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = chacha.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text chacha.decrypt(nonce, cipher_text, aad) ``` Example using `AESGCM`: ``` import os # Import AESGCM from cryptography from cryptography.hazmat.primitives.ciphers.aead import AESGCM # Our plaintext to encrypt plain_text = b"Secret text to encrypt" # We do not require authenticated but unencrypted data, so set to None aad = None # Generate a secure key key = AESGCM.generate_key(bit_length=128) # Create a new AESGCM instance with our secure key aesgcm = AESGCM(key) # Note: nonce values _must_ be regenerated every time they are used. nonce = os.urandom(12) # Encrypt our plaintext cipher_text = aesgcm.encrypt(nonce, plain_text, aad) # Decrypt the plain text using the nonce and cipher_text aesgcm.decrypt(nonce, cipher_text, aad) ``` For more information on the cryptography module see: - https://cryptography.io/en/latest/

No author info

The application was found using an FTP library. As FTP does not provide encryption, it is strongly recommended that any file transfers be done over a more secure transport such as SSH. The [paramiko](https://www.paramiko.org/) library can be used with an SCP module to allow secure file transfers. Example using `paramiko` SSH client and the `scp` module: ``` import paramiko import scp # Create an SSH client with paramiko.SSHClient() as ssh: # Load the system host keys so we can confirm the # host we are connecting to is legitimate ssh.load_system_host_keys('/home/appuser/.ssh/known_hosts') # Connect to the remote host using our SSH private key ssh.connect(hostname='example.org', port=22, username='appuser', key_filename='/home/appuser/.ssh/private_key') # Create an SCP client with the ssh transport and copy files with scp.SCPClient(ssh.get_transport()) as secure_copy: secure_copy.get('remote/test.file', 'local/test.file') secure_copy.put('local/some.file', 'remote/some.file') ``` For more information on the paramiko module see: - https://www.paramiko.org/ For more information on the scp module see: - https://github.com/jbardin/scp.py

No author info

The HTTPSConnection API has changed frequently with minor releases of Python.Ensure you are using the API for your version of Python securely. For example, Python 3 versions prior to 3.4.3 will not verify SSL certificates by default.

No author info

Detected a dynamic value being used with urllib. urllib supports `file://` schemes, so a dynamic value controlled by a malicious actor may allow them to read arbitrary files. Audit uses of urllib calls to ensure user data cannot control the URLs, or consider using the `requests` library instead.

No author info

Using various methods to parse untrusted XML data is known to be vulnerable to XML attacks. Replace vulnerable imports with the equivalent defusedxml package.

No author info

Using various methods to parse untrusted XML data is known to be vulnerable to XML attacks. Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is called.

No author info

Using various methods to parse untrusted XML data is known to be vulnerable to XML attacks. Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is called.