Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(python): extend and add rules following benchmarking #452

Merged
merged 16 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions rules/python/django/cookie_missing_http_only.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ auxiliary:
values: [render]
- id: python_django_cookie_missing_http_only_set_cookie_http_only
patterns:
- pattern: $<_>($<...>httponly=$<TRUE>$<...>)
# ok if it is not False
- pattern: $<_>($<...>httponly=$<FALSE>$<...>)
filters:
- variable: "TRUE"
detection: python_django_cookie_missing_http_only_true
scope: cursor
- id: python_django_cookie_missing_http_only_true
- not:
variable: "FALSE"
detection: python_django_cookie_missing_http_only_false
scope: cursor
- id: python_django_cookie_missing_http_only_false
patterns:
- "True"
- "False"
languages:
- python
severity: medium
Expand Down
14 changes: 8 additions & 6 deletions rules/python/django/cookie_missing_secure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ auxiliary:
values: [render]
- id: python_django_cookie_missing_secure_set_cookie_secure
patterns:
- pattern: $<_>($<...>secure=$<TRUE>)
# ok if it is not False
- pattern: $<_>($<...>secure=$<FALSE>$<...>)
filters:
- variable: "TRUE"
detection: python_django_cookie_missing_secure_true
scope: cursor
- id: python_django_cookie_missing_secure_true
- not:
variable: "FALSE"
detection: python_django_cookie_missing_secure_false
scope: cursor
- id: python_django_cookie_missing_secure_false
patterns:
- "True"
- "False"
languages:
- python
severity: medium
Expand Down
26 changes: 26 additions & 0 deletions rules/python/django/html_magic_method.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
patterns:
- |
def __html__($<...>):
languages:
- python
severity: high
metadata:
description: Usage of __html__ magic method
remediation_message: |
## Description

The Django template engine considers values returned by the `__html__` method as "safe" for rendering and therefore no HTML escaping is applied (escaping special characters like ampersands or quotes). Using this method exposes your application to Cross-Site Scripting (XSS) vulnerabilities.

## Remediations

- **Do not** use the `__html__` magic method
- **Do** use `format_html` instead to build up HTML fragments. This is more appropriate because it applies escaping to its arguments by default.
```python
from django.utils.html import format_html

format_html("{} <b>{}</b> {}", mark_safe(some_html), some text)
```
cwe_id:
- 79
id: python_django_html_magic_method
documentation_url: https://docs.bearer.com/reference/rules/python_django_html_magic_method
25 changes: 18 additions & 7 deletions rules/python/django/insecure_allow_origin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ patterns:
detection: python_shared_common_user_input
scope: result
- pattern: |
$<RESPONSE>($<...> headers={$<...>$<ALLOW_ORIGIN>: $<...>$<USER_INPUT>$<...>} $<...>)
$<RESPONSE>($<...>headers=$<HEADERS_HASH>$<...>)
filters:
- variable: RESPONSE
detection: python_shared_lang_import2
Expand All @@ -25,12 +25,23 @@ patterns:
- variable: MODULE2
values: [http]
- variable: NAME
values: [HttpResponse]
- variable: ALLOW_ORIGIN
string_regex: (?i)\Aaccess-control-allow-origin\z
- variable: USER_INPUT
detection: python_shared_common_user_input
scope: result
values:
- HttpResponse
- JsonResponse
- variable: HEADERS_HASH
detection: python_django_insecure_allow_origin_headers_hash
scope: cursor
auxiliary:
- id: python_django_insecure_allow_origin_headers_hash
patterns:
- pattern: |
{$<...>$<ALLOW_ORIGIN>: $<USER_INPUT>$<...>}
filters:
- variable: ALLOW_ORIGIN
string_regex: (?i)\Aaccess-control-allow-origin\z
- variable: USER_INPUT
detection: python_shared_common_user_input
scope: result
languages:
- python
severity: medium
Expand Down
58 changes: 58 additions & 0 deletions rules/python/django/mark_safe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
imports:
- python_shared_lang_import3
sanitizer: python_django_mark_safe_sanitizer
patterns:
- pattern: $<MARK_SAFE>($<...>)
filters:
- variable: MARK_SAFE
detection: python_shared_lang_import3
scope: cursor
filters:
- variable: MODULE1
values: [django]
- variable: MODULE2
values: [utils]
- variable: MODULE3
values: [safestring]
- variable: NAME
values: [mark_safe]
auxiliary:
- id: python_django_mark_safe_sanitizer
patterns:
- pattern: $<FORMAT_HTML>($<...>)
filters:
- variable: FORMAT_HTML
detection: python_shared_lang_import3
scope: cursor
filters:
- variable: MODULE1
values: [django]
- variable: MODULE2
values: [utils]
- variable: MODULE3
values: [html]
- variable: NAME
values: [format_html]
languages:
- python
severity: high
metadata:
description: Usage of mark_safe
remediation_message: |
## Description

The Django utils method `mark_safe` is used to mark a string as "safe" for output as HTML, but it does not escape special characters like ampersands or quotes, and therefore could expose your application to XSS attacks if an external string is passed to it.

## Remediations

- **Do not** use `mark_safe` wherever possible
- **Do** use `format_html` instead to build up HTML fragments. This is more appropriate because it applies escaping to its arguments by default.
```python
from django.utils.html import format_html

format_html("{} <b>{}</b> {}", mark_safe(some_html), some text)
```
cwe_id:
- 79
id: python_django_mark_safe
documentation_url: https://docs.bearer.com/reference/rules/python_django_mark_safe
23 changes: 17 additions & 6 deletions rules/python/django/permissive_allow_origin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ patterns:
- variable: VALUE
string_regex: \A\*\z
- pattern: |
$<RESPONSE>($<...> headers={$<...>$<ALLOW_ORIGIN>: $<...>$<VALUE>$<...>} $<...>)
$<RESPONSE>($<...>headers=$<HEADERS_HASH>$<...>)
filters:
- variable: RESPONSE
detection: python_shared_lang_import2
Expand All @@ -23,11 +23,22 @@ patterns:
- variable: MODULE2
values: [http]
- variable: NAME
values: [HttpResponse]
- variable: ALLOW_ORIGIN
string_regex: (?i)\Aaccess-control-allow-origin\z
- variable: VALUE
string_regex: \A\*\z
values:
- HttpResponse
- JsonResponse
- variable: HEADERS_HASH
detection: python_django_permissive_allow_origin_headers_hash
scope: cursor
auxiliary:
- id: python_django_permissive_allow_origin_headers_hash
patterns:
- pattern: |
{$<...>$<ALLOW_ORIGIN>: $<VALUE>$<...>}
filters:
- variable: ALLOW_ORIGIN
string_regex: (?i)\Aaccess-control-allow-origin\z
- variable: VALUE
string_regex: \A\*\z
languages:
- python
severity: medium
Expand Down
74 changes: 74 additions & 0 deletions rules/python/lang/avoid_pickle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
imports:
- python_shared_lang_import1
patterns:
- pattern: $<PICKLE>($<...>)
filters:
- variable: PICKLE
detection: python_shared_lang_import1
scope: cursor
filters:
- variable: MODULE1
values:
- pickle
- _pickle
- cPickle
- variable: NAME
values:
- load
- loads
- dump
- dumps
- pattern: $<UNPICKLER>.$<METHOD>()
filters:
- variable: UNPICKLER
detection: python_lang_avoid_pickle_unpickler
scope: cursor
- variable: METHOD
values:
- load
- persistent_load
auxiliary:
- id: python_lang_avoid_pickle_unpickler
patterns:
- pattern: $<UNPICKLER>($<...>)
filters:
- variable: UNPICKLER
detection: python_shared_lang_import1
scope: cursor
filters:
- variable: MODULE1
values:
- pickle
- _pickle
- cPickle
- variable: NAME
values: [Unpickler]
languages:
- python
severity: critical
metadata:
description: Usage of unsafe Pickle libraries
remediation_message: |
## Description

Using pickle, _pickle and cPickle can make your application vulnerable to unsafe code execution. This is because the deserialization logic of these libraries allows for arbitrary code execution. It is best practices to avoid these libraries and to use a safer serialization formats like JSON.

## Remediations

- **Do not** use pickle or its derivatives for deserialization wherever possible. These libraries are open to security vulnerabilities.
- **Do** use recommended safer formats like JSON, Protocol Buffers (protobuf) and MessagePack.
```python
import msgpack #MessagePack

data = {'key': 'value'}
packed_data = msgpack.packb(data)
```

## References

- [OWASP Deserialization cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html)

cwe_id:
- 502
id: python_lang_avoid_pickle
documentation_url: https://docs.bearer.com/reference/rules/python_lang_avoid_pickle
54 changes: 41 additions & 13 deletions rules/python/lang/code_injection.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,46 @@
imports:
- python_shared_common_user_input
- python_shared_common_external_input
- python_shared_lang_import1
patterns:
- pattern: exec($<...>$<USER_INPUT>$<...>)
- pattern: exec($<...>$<EXTERNAL_INPUT>$<...>)
filters:
- variable: USER_INPUT
detection: python_shared_common_user_input
- variable: EXTERNAL_INPUT
detection: python_shared_common_external_input
scope: result
- pattern: setattr($<_>, $<_>, $<...>$<USER_INPUT>$<...>)
- pattern: setattr($<_>, $<_>, $<...>$<EXTERNAL_INPUT>$<...>)
filters:
- variable: USER_INPUT
detection: python_shared_common_user_input
- variable: EXTERNAL_INPUT
detection: python_shared_common_external_input
scope: result
- pattern: $<OS>($<...>$<USER_INPUT>$<...>)
- pattern: compile($<_>, $<_>, $<...>$<EXTERNAL_INPUT>$<...>)
filters:
- variable: EXTERNAL_INPUT
detection: python_shared_common_external_input
scope: result
- pattern: $<IMPORT_MODULE>($<...>$<EXTERNAL_INPUT>$<...>)
filters:
- variable: IMPORT_MODULE
detection: python_shared_lang_import1
scope: cursor
filters:
- variable: MODULE1
values: [importlib]
- variable: NAME
values: [import_module]
- variable: EXTERNAL_INPUT
detection: python_shared_common_external_input
scope: result
- pattern: __import__($<...>$<EXTERNAL_INPUT>$<...>)
filters:
- variable: EXTERNAL_INPUT
detection: python_shared_common_external_input
scope: result
- pattern: globals()[$<...>$<EXTERNAL_INPUT>$<...>]
filters:
- variable: EXTERNAL_INPUT
detection: python_shared_common_external_input
scope: result
- pattern: $<OS>($<...>$<EXTERNAL_INPUT>$<...>)
filters:
- variable: OS
detection: python_shared_lang_import1
Expand All @@ -30,22 +58,22 @@ patterns:
- execve
- execvp
- execvpe
- variable: USER_INPUT
detection: python_shared_common_user_input
- variable: EXTERNAL_INPUT
detection: python_shared_common_external_input
scope: result
languages:
- python
severity: critical
metadata:
description: Unsanitized user input in code generation
description: Unsanitized external input in code generation
remediation_message: |-
## Description

Allowing user input to directly influence code generation or scripting functions without proper sanitization can lead to code injection vulnerabilities. This occurs when an attacker is able to insert malicious code into your application, which is then executed, potentially leading to unauthorized actions or data access.
Allowing external input (dynamic or user-controlled) to directly influence code generation or scripting functions without proper sanitization can lead to code injection vulnerabilities. This occurs when an attacker is able to insert malicious code into your application, which is then executed, potentially leading to unauthorized actions or data access.

## Remediations

- **Do not** pass unsanitized user input to functions or methods that dynamically execute code.
- **Do not** pass unsanitized external input to functions or methods that dynamically execute code.
- **Do** always validate or sanitize input to ensure it does not contain harmful code before using it in such contexts.

## References
Expand Down
4 changes: 2 additions & 2 deletions rules/python/lang/http_url_using_user_input.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ languages:
- python
imports:
- python_shared_common_user_input
- python_shared_lang_http_location
- python_shared_common_http_location
patterns:
- pattern: $<USER_INPUT_LOCATION>
filters:
- variable: USER_INPUT_LOCATION
detection: python_shared_lang_http_location
detection: python_shared_common_http_location
scope: cursor_strict
filters:
- variable: LOCATION
Expand Down
Loading
Loading