Skip to content

Commit

Permalink
feat(python): extend and add rules following benchmarking (#452)
Browse files Browse the repository at this point in the history
  • Loading branch information
elsapet authored Jun 18, 2024
1 parent 20753c7 commit 483d3e9
Show file tree
Hide file tree
Showing 40 changed files with 806 additions and 76 deletions.
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

0 comments on commit 483d3e9

Please sign in to comment.