Skip to content

Commit

Permalink
feat: add http response splitting rule
Browse files Browse the repository at this point in the history
  • Loading branch information
didroe committed May 16, 2024
1 parent 41fb814 commit 586e6b0
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 0 deletions.
54 changes: 54 additions & 0 deletions rules/python/lang/http_response_splitting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
imports:
- python_shared_common_user_input
- python_shared_lang_http_server_handler
patterns:
- pattern: $<HANDLER>.send_header($<...>$<USER_INPUT>$<...>)
filters:
- variable: HANDLER
detection: python_shared_lang_http_server_handler
scope: cursor
- variable: USER_INPUT
detection: python_lang_http_response_splitting_user_input
scope: result
auxiliary:
- id: python_lang_http_response_splitting_user_input
sanitizer: python_lang_http_response_splitting_sanitizer
patterns:
- pattern: $<UNSANITIZED_USER_INPUT>
filters:
- variable: UNSANITIZED_USER_INPUT
detection: python_shared_common_user_input
scope: cursor
- id: python_lang_http_response_splitting_sanitizer
patterns:
- pattern: $<ORIGINAL>.replace($<SOURCE>, $<REPLACEMENT>)
focus: ORIGINAL
filters:
- variable: SOURCE
string_regex: "\\r\\n|\\\\r\\\\n"
- not:
variable: REPLACEMENT
string_regex: "\\r\\n|\\\\r\\\\n"
languages:
- python
severity: high
metadata:
description: "Unsanitized user input in HTTP response (XSS)"
remediation_message: |-
## Description
Including unsanitized user input in a HTTP response could allow an attacker inject Carriage Return Line Feed (CRLF) characters into the response. An entirely attacker-controlled response can then be returned, creating a cross-site scripting (XSS) vulnerability.
## Remediations
- **Do not** include user input in cookies or other HTTP headers without proper sanitization. This can prevent attackers from exploiting the input to manipulate the response.
- **Do** remove CRLF sequences from user input to mitigate the risk of response splitting and XSS attacks. Use the following code snippet as a reference for sanitizing input in Java:
```python
input = request.getParameter("data");
var sanitized = input.replaceAll("\r\n", "");
cookie.setValue(sanitized);
```
cwe_id:
- 79
id: python_lang_http_response_splitting
documentation_url: https://docs.bearer.com/reference/rules/python_lang_http_response_splitting
26 changes: 26 additions & 0 deletions rules/python/shared/lang/http_server_handler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
type: shared
languages:
- python
imports:
- python_shared_lang_instance
- python_shared_lang_import2
patterns:
- pattern: $<INSTANCE>
filters:
- variable: INSTANCE
detection: python_shared_lang_instance
scope: cursor_strict
filters:
- variable: CLASS
detection: python_shared_lang_import2
scope: cursor
filters:
- variable: MODULE1
values: [http]
- variable: MODULE2
values: [server]
- variable: NAME
values: [BaseHTTPRequestHandler]
metadata:
description: "Python http.server handler instance"
id: python_shared_lang_http_server_handler
7 changes: 7 additions & 0 deletions rules/python/shared/lang/user_input.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
type: shared
languages:
- python
imports:
- python_shared_lang_http_server_handler
patterns:
- input($<...>)
- pattern: $<HANDLER>.path
filters:
- variable: HANDLER
detection: python_shared_lang_http_server_handler
scope: cursor
metadata:
description: "Python lang user input."
id: python_shared_lang_user_input
20 changes: 20 additions & 0 deletions tests/python/lang/http_response_splitting/test.js
Original file line number Diff line number Diff line change
@@ -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("http_response_splitting", () => {
const testCase = "main.py"

const results = invoke(testCase)

expect(results).toEqual({
Missing: [],
Extra: []
})
})
})
32 changes: 32 additions & 0 deletions tests/python/lang/http_response_splitting/testdata/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# this file is also testing the shared instance rule

from http.server import BaseHTTPRequestHandler

class WebRequestHandler(BaseHTTPRequestHandler, Foo):
def do_GET(self):
self.send_header("ok", "ok")

# bearer:expected python_lang_http_response_splitting
self.send_header(self.path, "ok")

def do_POST(self):
self.send_header(self.path.replace("\r\n", ""), "ok")
self.send_header("ok", self.path.replace("\r\n", ""))

# bearer:expected python_lang_http_response_splitting
self.send_header("ok", self.path)


# contrived examples for testing instance rule
class Other:
def m(self, x: BaseHTTPRequestHandler) -> string:
# bearer:expected python_lang_http_response_splitting
x.send_header(input(), "ok")

y = BaseHTTPRequestHandler(foo)
# bearer:expected python_lang_http_response_splitting
y.send_header(input(), "ok")

def m(self, z: BaseHTTPRequestHandler = default) -> string:
# bearer:expected python_lang_http_response_splitting
z.send_header(input(), "ok")

0 comments on commit 586e6b0

Please sign in to comment.