diff --git a/rules/python/django/crlf_injection.yml b/rules/python/django/crlf_injection.yml new file mode 100644 index 00000000..dfcfd74a --- /dev/null +++ b/rules/python/django/crlf_injection.yml @@ -0,0 +1,51 @@ +imports: + - python_shared_common_user_input +patterns: + - pattern: | + $.write($$<...>) + filters: + - variable: FILE + detection: python_django_crlf_injection_file + scope: cursor + - variable: USER_INPUT + detection: python_shared_common_user_input + scope: result + - not: + variable: USER_INPUT + detection: python_django_crlf_injection_sanitized_dynamic_input + scope: result +auxiliary: + - id: python_django_crlf_injection_file + patterns: + - open($<...>) + - id: python_django_crlf_injection_sanitized_dynamic_input + patterns: + - $<_>.strip() + - pattern: $<_>.strip($) + filters: + - variable: SOURCE + string_regex: \A(\\r\\n|\\n\\r)n\z +languages: + - python +severity: medium +metadata: + description: Possible CLRF injection detected + remediation_message: |- + ## Description + + CRLF (Carriage Return Line Feed) injection vulnerability occurs when an attacker is able to insert a sequence of line termination characters into a log message or a file. This can lead to forged log entries, compromising the integrity of log files, or worse, a denial-of-service (DoS) if an attacker abuses the vulnerability by using up all available disk space. + + ## Remediations + + - **Do** strip any carriage return and line feed characters from user input data before logging it or writing to a file. This prevents attackers from injecting malicious CRLF sequences. + ```pyhton + response.write(user_input.replaceAll("[\r\n]+", "")); + ``` + + ## References + + - [OWASP CRLF Injection](https://owasp.org/www-community/vulnerabilities/CRLF_Injection) + cwe_id: + - 93 + id: python_django_crlf_injection + documentation_url: https://docs.bearer.com/reference/rules/python_django_crlf_injection diff --git a/tests/python/django/crlf_injection/test.js b/tests/python/django/crlf_injection/test.js new file mode 100644 index 00000000..6f8e133f --- /dev/null +++ b/tests/python/django/crlf_injection/test.js @@ -0,0 +1,20 @@ +const { + createNewInvoker, + getEnvironment, +} = require("../../../helper.js") +const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) + +describe(ruleId, () => { + const invoke = createNewInvoker(ruleId, ruleFile, testBase) + + test("crlf_injection", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/django/crlf_injection/testdata/main.py b/tests/python/django/crlf_injection/testdata/main.py new file mode 100644 index 00000000..42f97444 --- /dev/null +++ b/tests/python/django/crlf_injection/testdata/main.py @@ -0,0 +1,17 @@ +def bad(request): + log_code = request.POST.get('log_code') + log_filename = os.path.join(dirname, "my-log-code.py") + f = open(log_filename,"w") + # bearer:expected python_django_crlf_injection + f.write(log_code) + f.close() + +def ok(request): + log_code = request.POST.get('log_code') + log_filename = os.path.join(dirname, "my-log-code.py") + f = open(log_filename,"w") + # ok + f.write(log_code.strip()) + # ok + f.write(log_code.strip("\r\n")) + f.close() \ No newline at end of file