{
"command": "git status && git diff --stat && ls",
"description": "Check git status and diff"
}On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: bottle.py
no changes added to commit (use "git add" and/or "git commit -a")
bottle.py | 4 ----
1 file changed, 4 deletions(-)
AUTHORS
LICENSE
Makefile
README.rst
bottle.py
docs
pyproject.toml
test
[stdout]
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: bottle.py
no changes added to commit (use "git add" and/or "git commit -a")
bottle.py | 4 ----
1 file changed, 4 deletions(-)
AUTHORS
LICENSE
Makefile
README.rst
bottle.py
docs
pyproject.toml
test
[metadata] {"noOutputExpected": false}{
"command": "wc -l bottle.py && ls test/",
"description": "Check file size and tests"
}4576 bottle.py
__init__.py
build_python.sh
example_settings.py
test_app.py
test_auth.py
test_config.py
test_contextlocals.py
test_environ.py
test_exc.py
test_fileupload.py
test_formsdict.py
test_html_helper.py
test_importhook.py
test_jinja2.py
test_mako.py
test_mdict.py
test_mount.py
test_multipart.py
test_oorouting.py
test_outputfilter.py
test_plugins.py
test_resources.py
test_route.py
test_router.py
test_securecookies.py
test_sendfile.py
test_stpl.py
test_wsgi.py
tools.py
views
[stdout]
4576 bottle.py
__init__.py
build_python.sh
example_settings.py
test_app.py
test_auth.py
test_config.py
test_contextlocals.py
test_environ.py
test_exc.py
test_fileupload.py
test_formsdict.py
test_html_helper.py
test_importhook.py
test_jinja2.py
test_mako.py
test_mdict.py
test_mount.py
test_multipart.py
test_oorouting.py
test_outputfilter.py
test_plugins.py
test_resources.py
test_route.py
test_router.py
test_securecookies.py
test_sendfile.py
test_stpl.py
test_wsgi.py
tools.py
views
[metadata] {"noOutputExpected": false}{
"command": "git diff",
"description": "Show the working tree diff"
}diff --git a/bottle.py b/bottle.py
index a297ca9..d1e4022 100755
--- a/bottle.py
+++ b/bottle.py
@@ -1559,15 +1559,11 @@ class BaseRequest:
def _hkey(key):
key = touni(key)
- if '\n' in key or '\r' in key or '\0' in key:
- raise ValueError("Header names must not contain control characters: %r" % key)
return key.title().replace('_', '-')
def _hval(value):
value = touni(value)
- if '\n' in value or '\r' in value or '\0' in value:
- raise ValueError("Header value must not contain control characters: %r" % value)
return value
[stdout]
diff --git a/bottle.py b/bottle.py
index a297ca9..d1e4022 100755
--- a/bottle.py
+++ b/bottle.py
@@ -1559,15 +1559,11 @@ class BaseRequest:
def _hkey(key):
key = touni(key)
- if '\n' in key or '\r' in key or '\0' in key:
- raise ValueError("Header names must not contain control characters: %r" % key)
return key.title().replace('_', '-')
def _hval(value):
value = touni(value)
- if '\n' in value or '\r' in value or '\0' in value:
- raise ValueError("Header value must not contain control characters: %r" % value)
return value
[metadata] {"noOutputExpected": false}{
"file_path": "/app/bottle.py",
"offset": 1550,
"limit": 30
}1550 raise AttributeError("Attribute already defined: %s" % name)
1551 self.environ[key] = value
1552
1553 def __delattr__(self, name):
1554 try:
1555 del self.environ['bottle.request.ext.%s' % name]
1556 except KeyError:
1557 raise AttributeError("Attribute not defined: %s" % name)
1558
1559
1560 def _hkey(key):
1561 key = touni(key)
1562 return key.title().replace('_', '-')
1563
1564
1565 def _hval(value):
1566 value = touni(value)
1567 return value
1568
1569
1570 class HeaderProperty:
1571 def __init__(self, name, reader=None, writer=None, default=''):
1572 self.name, self.default = name, default
1573 self.reader, self.writer = reader, writer
1574 self.__doc__ = 'Current value of the %r header.' % name.title()
1575
1576 def __get__(self, obj, _):
1577 if obj is None: return self
1578 value = obj.get_header(self.name, self.default)
1579 return self.reader(value) if self.reader else value
[metadata] {"type": "text", "file": {"filePath": "/app/bottle.py", "content": " raise AttributeError(\"Attribute already defined: %s\" % name)\n self.environ[key] = value\n\n def __delattr__(self, name):\n try:\n del self.environ['bottle.request.ext.%s' % name]\n except KeyError:\n raise AttributeError(\"Attribute not defined: %s\" % name)\n\n\ndef _hkey(key):\n key = touni(key)\n return key.title().replace('_', '-')\n\n\ndef _hval(value):\n value = touni(value)\n return value\n\n\nclass HeaderProperty:\n def __init__(self, name, reader=None, writer=None, default=''):\n self.name, self.default = name, default\n self.reader, self.writer = reader, writer\n self.__doc__ = 'Current value of the %r header.' % name.title()\n\n def __get__(self, obj, _):\n if obj is None: return self\n value = obj.get_header(self.name, self.default)\n return self.reader(value) if self.reader else value", "numLines": 30, "startLine": 1550, "totalLines": 4577}}{
"command": "grep -rn \"_hkey\\|_hval\\|control characters\" /app/bottle.py /app/test/ | head -50",
"description": "Find usages of _hkey/_hval and related tests"
}/app/bottle.py:1560:def _hkey(key):
/app/bottle.py:1565:def _hval(value):
/app/bottle.py:1699: return _hkey(name) in self._headers
/app/bottle.py:1702: del self._headers[_hkey(name)]
/app/bottle.py:1705: return self._headers[_hkey(name)][-1]
/app/bottle.py:1708: self._headers[_hkey(name)] = [_hval(value)]
/app/bottle.py:1713: return self._headers.get(_hkey(name), [default])[-1]
/app/bottle.py:1718: self._headers[_hkey(name)] = [_hval(value)]
/app/bottle.py:1722: self._headers.setdefault(_hkey(name), []).append(_hval(value))
/app/bottle.py:1746: out.append(('Set-Cookie', _hval(c.OutputString())))
/app/bottle.py:2177: return _hkey(key) in self.dict
/app/bottle.py:2180: del self.dict[_hkey(key)]
/app/bottle.py:2183: return self.dict[_hkey(key)][-1]
/app/bottle.py:2186: self.dict[_hkey(key)] = [_hval(value)]
/app/bottle.py:2189: self.dict.setdefault(_hkey(key), []).append(_hval(value))
/app/bottle.py:2192: self.dict[_hkey(key)] = [_hval(value)]
/app/bottle.py:2195: return self.dict.get(_hkey(key)) or []
/app/bottle.py:2198: return MultiDict.get(self, _hkey(key), default, index)
/app/bottle.py:2201: for name in (_hkey(n) for n in names):
/app/bottle.py:2239: yield _hkey(key[5:])
/app/bottle.py:2241: yield _hkey(key)
[stdout]
/app/bottle.py:1560:def _hkey(key):
/app/bottle.py:1565:def _hval(value):
/app/bottle.py:1699: return _hkey(name) in self._headers
/app/bottle.py:1702: del self._headers[_hkey(name)]
/app/bottle.py:1705: return self._headers[_hkey(name)][-1]
/app/bottle.py:1708: self._headers[_hkey(name)] = [_hval(value)]
/app/bottle.py:1713: return self._headers.get(_hkey(name), [default])[-1]
/app/bottle.py:1718: self._headers[_hkey(name)] = [_hval(value)]
/app/bottle.py:1722: self._headers.setdefault(_hkey(name), []).append(_hval(value))
/app/bottle.py:1746: out.append(('Set-Cookie', _hval(c.OutputString())))
/app/bottle.py:2177: return _hkey(key) in self.dict
/app/bottle.py:2180: del self.dict[_hkey(key)]
/app/bottle.py:2183: return self.dict[_hkey(key)][-1]
/app/bottle.py:2186: self.dict[_hkey(key)] = [_hval(value)]
/app/bottle.py:2189: self.dict.setdefault(_hkey(key), []).append(_hval(value))
/app/bottle.py:2192: self.dict[_hkey(key)] = [_hval(value)]
/app/bottle.py:2195: return self.dict.get(_hkey(key)) or []
/app/bottle.py:2198: return MultiDict.get(self, _hkey(key), default, index)
/app/bottle.py:2201: for name in (_hkey(n) for n in names):
/app/bottle.py:2239: yield _hkey(key[5:])
/app/bottle.py:2241: yield _hkey(key)
[metadata] {"noOutputExpected": false}{
"command": "grep -rn \"ValueError\\|\\\\\\\\n\\|header\" /app/test/test_environ.py | grep -i \"valueerror\\|inject\\|crlf\\|control\" ",
"description": "Search tests for header injection expectations"
}/app/test/test_environ.py:531: self.assertRaises(ValueError, test)
/app/test/test_environ.py:537: self.assertRaises(ValueError, test)
/app/test/test_environ.py:558: self.assertRaises(ValueError, test)
/app/test/test_environ.py:564: self.assertRaises(ValueError, test)
/app/test/test_environ.py:570: self.assertRaises(ValueError, test)
/app/test/test_environ.py:576: self.assertRaises(ValueError, test)
/app/test/test_environ.py:613: self.assertRaises(ValueError, r.set_cookie, name='test', value='x' * 4097)
/app/test/test_environ.py:617: self.assertRaises(ValueError, r.set_cookie, name='x' * 4097, value='simple_value')
/app/test/test_environ.py:735: def test_prevent_control_characters_in_headers(self):
/app/test/test_environ.py:745: self.assertRaises(ValueError, func, value, "test-value")
/app/test/test_environ.py:746: self.assertRaises(ValueError, func, "test-name", value)
/app/test/test_environ.py:754: self.assertRaises(ValueError, func, value, "test-value")
/app/test/test_environ.py:755: self.assertRaises(ValueError, func, "test-name", value)
[stdout]
/app/test/test_environ.py:531: self.assertRaises(ValueError, test)
/app/test/test_environ.py:537: self.assertRaises(ValueError, test)
/app/test/test_environ.py:558: self.assertRaises(ValueError, test)
/app/test/test_environ.py:564: self.assertRaises(ValueError, test)
/app/test/test_environ.py:570: self.assertRaises(ValueError, test)
/app/test/test_environ.py:576: self.assertRaises(ValueError, test)
/app/test/test_environ.py:613: self.assertRaises(ValueError, r.set_cookie, name='test', value='x' * 4097)
/app/test/test_environ.py:617: self.assertRaises(ValueError, r.set_cookie, name='x' * 4097, value='simple_value')
/app/test/test_environ.py:735: def test_prevent_control_characters_in_headers(self):
/app/test/test_environ.py:745: self.assertRaises(ValueError, func, value, "test-value")
/app/test/test_environ.py:746: self.assertRaises(ValueError, func, "test-name", value)
/app/test/test_environ.py:754: self.assertRaises(ValueError, func, value, "test-value")
/app/test/test_environ.py:755: self.assertRaises(ValueError, func, "test-name", value)
[metadata] {"noOutputExpected": false}{
"command": "grep -rn \"ValueError\" /app/test/*.py",
"description": "Grep all tests for ValueError"
}/app/test/test_config.py:66: self.assertRaises(ValueError, lambda: c.update(int='not an int'))
/app/test/test_environ.py:531: self.assertRaises(ValueError, test)
/app/test/test_environ.py:537: self.assertRaises(ValueError, test)
/app/test/test_environ.py:558: self.assertRaises(ValueError, test)
/app/test/test_environ.py:564: self.assertRaises(ValueError, test)
/app/test/test_environ.py:570: self.assertRaises(ValueError, test)
/app/test/test_environ.py:576: self.assertRaises(ValueError, test)
/app/test/test_environ.py:613: self.assertRaises(ValueError, r.set_cookie, name='test', value='x' * 4097)
/app/test/test_environ.py:617: self.assertRaises(ValueError, r.set_cookie, name='x' * 4097, value='simple_value')
/app/test/test_environ.py:745: self.assertRaises(ValueError, func, value, "test-value")
/app/test/test_environ.py:746: self.assertRaises(ValueError, func, "test-name", value)
/app/test/test_environ.py:754: self.assertRaises(ValueError, func, value, "test-value")
/app/test/test_environ.py:755: self.assertRaises(ValueError, func, "test-name", value)
/app/test/test_router.py:58: def testValueErrorInFilter(self):
/app/test/test_router.py:129: self.assertRaises(ValueError, build, 'introute', 'hello')
[stdout]
/app/test/test_config.py:66: self.assertRaises(ValueError, lambda: c.update(int='not an int'))
/app/test/test_environ.py:531: self.assertRaises(ValueError, test)
/app/test/test_environ.py:537: self.assertRaises(ValueError, test)
/app/test/test_environ.py:558: self.assertRaises(ValueError, test)
/app/test/test_environ.py:564: self.assertRaises(ValueError, test)
/app/test/test_environ.py:570: self.assertRaises(ValueError, test)
/app/test/test_environ.py:576: self.assertRaises(ValueError, test)
/app/test/test_environ.py:613: self.assertRaises(ValueError, r.set_cookie, name='test', value='x' * 4097)
/app/test/test_environ.py:617: self.assertRaises(ValueError, r.set_cookie, name='x' * 4097, value='simple_value')
/app/test/test_environ.py:745: self.assertRaises(ValueError, func, value, "test-value")
/app/test/test_environ.py:746: self.assertRaises(ValueError, func, "test-name", value)
/app/test/test_environ.py:754: self.assertRaises(ValueError, func, value, "test-value")
/app/test/test_environ.py:755: self.assertRaises(ValueError, func, "test-name", value)
/app/test/test_router.py:58: def testValueErrorInFilter(self):
/app/test/test_router.py:129: self.assertRaises(ValueError, build, 'introute', 'hello')
[metadata] {"noOutputExpected": false}{
"file_path": "/app/test/test_environ.py",
"offset": 725,
"limit": 40
}725
726 def test_non_string_header(self):
727 response = BaseResponse()
728 response['x-test'] = 5
729 self.assertEqual('5', response['x-test'])
730 response['x-test'] = None
731 self.assertEqual('', response['x-test'])
732 response['x-test'] = touni('瓶')
733 self.assertEqual(touni('瓶'), response['x-test'])
734
735 def test_prevent_control_characters_in_headers(self):
736 masks = '{}test', 'test{}', 'te{}st'
737 tests = '\n', '\r', '\n\r', '\0'
738
739 # Test HeaderDict
740 apis = 'append', 'replace', '__setitem__', 'setdefault'
741 for api, mask, test in itertools.product(apis, masks, tests):
742 hd = bottle.HeaderDict()
743 func = getattr(hd, api)
744 value = mask.replace("{}", test)
745 self.assertRaises(ValueError, func, value, "test-value")
746 self.assertRaises(ValueError, func, "test-name", value)
747
748 # Test functions on BaseResponse
749 apis = 'add_header', 'set_header', '__setitem__'
750 for api, mask, test in itertools.product(apis, masks, tests):
751 rs = bottle.BaseResponse()
752 func = getattr(rs, api)
753 value = mask.replace("{}", test)
754 self.assertRaises(ValueError, func, value, "test-value")
755 self.assertRaises(ValueError, func, "test-name", value)
756
757 def test_expires_header(self):
758 import datetime
759 from bottle import UTC
760 response = BaseResponse()
761 now = datetime.datetime.now(UTC)
762 response.expires = now
763
764 def seconds(a, b):
[metadata] {"type": "text", "file": {"filePath": "/app/test/test_environ.py", "content": "\n def test_non_string_header(self):\n response = BaseResponse()\n response['x-test'] = 5\n self.assertEqual('5', response['x-test'])\n response['x-test'] = None\n self.assertEqual('', response['x-test'])\n response['x-test'] = touni('瓶')\n self.assertEqual(touni('瓶'), response['x-test'])\n\n def test_prevent_control_characters_in_headers(self):\n masks = '{}test', 'test{}', 'te{}st'\n tests = '\\n', '\\r', '\\n\\r', '\\0'\n\n # Test HeaderDict\n apis = 'append', 'replace', '__setitem__', 'setdefault'\n for api, mask, test in itertools.product(apis, masks, tests):\n hd = bottle.HeaderDict()\n func = getattr(hd, api)\n value = mask.replace(\"{}\", test)\n self.assertRaises(ValueError, func, value, \"test-value\")\n self.assertRaises(ValueError, func, \"test-name\", value)\n\n # Test functions on BaseResponse\n apis = 'add_header', 'set_header', '__setitem__'\n for api, mask, test in itertools.product(apis, masks, tests):\n rs = bottle.BaseResponse()\n func = getattr(rs, api)\n value = mask.replace(\"{}\", test)\n self.assertRaises(ValueError, func, value, \"test-value\")\n self.assertRaises(ValueError, func, \"test-name\", value)\n\n def test_expires_header(self):\n import datetime\n from bottle import UTC\n response = BaseResponse()\n now = datetime.datetime.now(UTC)\n response.expires = now\n\n def seconds(a, b):", "numLines": 40, "startLine": 725, "totalLines": 908}}{
"command": "python -m pytest test/test_environ.py -k control -rA 2>&1 | tail -20",
"description": "Run the control character test"
}self = <test.test_environ.TestResponse testMethod=test_prevent_control_characters_in_headers>
def test_prevent_control_characters_in_headers(self):
masks = '{}test', 'test{}', 'te{}st'
tests = '\n', '\r', '\n\r', '\0'
# Test HeaderDict
apis = 'append', 'replace', '__setitem__', 'setdefault'
for api, mask, test in itertools.product(apis, masks, tests):
hd = bottle.HeaderDict()
func = getattr(hd, api)
value = mask.replace("{}", test)
> self.assertRaises(ValueError, func, value, "test-value")
E AssertionError: ValueError not raised by append
test/test_environ.py:745: AssertionError
=========================== short test summary info ============================
FAILED test/test_environ.py::TestResponse::test_prevent_control_characters_in_headers
======================= 1 failed, 74 deselected in 0.13s =======================
[stdout]
self = <test.test_environ.TestResponse testMethod=test_prevent_control_characters_in_headers>
def test_prevent_control_characters_in_headers(self):
masks = '{}test', 'test{}', 'te{}st'
tests = '\n', '\r', '\n\r', '\0'
# Test HeaderDict
apis = 'append', 'replace', '__setitem__', 'setdefault'
for api, mask, test in itertools.product(apis, masks, tests):
hd = bottle.HeaderDict()
func = getattr(hd, api)
value = mask.replace("{}", test)
> self.assertRaises(ValueError, func, value, "test-value")
E AssertionError: ValueError not raised by append
test/test_environ.py:745: AssertionError
=========================== short test summary info ============================
FAILED test/test_environ.py::TestResponse::test_prevent_control_characters_in_headers
======================= 1 failed, 74 deselected in 0.13s =======================
[metadata] {"noOutputExpected": false}{
"replace_all": false,
"file_path": "/app/bottle.py",
"old_string": "def _hkey(key):\n key = touni(key)\n return key.title().replace('_', '-')\n\n\ndef _hval(value):\n value = touni(value)\n return value",
"new_string": "def _hkey(key):\n key = touni(key)\n if '\\n' in key or '\\r' in key or '\\0' in key:\n raise ValueError(\"Header names must not contain control characters: %r\" % key)\n return key.title().replace('_', '-')\n\n\ndef _hval(value):\n value = touni(value)\n if '\\n' in value or '\\r' in value or '\\0' in value:\n raise ValueError(\"Header value must not contain control characters: %r\" % value)\n return value"
}The file /app/bottle.py has been updated successfully. (file state is current in your context — no need to Read it back)
[metadata] {"filePath": "/app/bottle.py", "oldString": "def _hkey(key):\n key = touni(key)\n return key.title().replace('_', '-')\n\n\ndef _hval(value):\n value = touni(value)\n return value", "newString": "def _hkey(key):\n key = touni(key)\n if '\\n' in key or '\\r' in key or '\\0' in key:\n raise ValueError(\"Header names must not contain control characters: %r\" % key)\n return key.title().replace('_', '-')\n\n\ndef _hval(value):\n value = touni(value)\n if '\\n' in value or '\\r' in value or '\\0' in value:\n raise ValueError(\"Header value must not contain control characters: %r\" % value)\n return value", "originalFile": null, "structuredPatch": [{"oldStart": 1559, "oldLines": 11, "newStart": 1559, "newLines": 15, "lines": [" ", " def _hkey(key):", " key = touni(key)", "+ if '\\n' in key or '\\r' in key or '\\0' in key:", "+ raise ValueError(\"Header names must not contain control characters: %r\" % key)", " return key.title().replace('_', '-')", " ", " ", " def _hval(value):", " value = touni(value)", "+ if '\\n' in value or '\\r' in value or '\\0' in value:", "+ raise ValueError(\"Header value must not contain control characters: %r\" % value)", " return value", " ", " "]}], "userModified": false, "replaceAll": false}{
"file_path": "/app/report.jsonl",
"content": "{\"file_path\": \"/app/bottle.py\", \"cwe_id\": [\"cwe-93\", \"cwe-113\", \"cwe-20\"]}\n"
}File created successfully at: /app/report.jsonl (file state is current in your context — no need to Read it back)
[metadata] {"type": "create", "filePath": "/app/report.jsonl", "content": "{\"file_path\": \"/app/bottle.py\", \"cwe_id\": [\"cwe-93\", \"cwe-113\", \"cwe-20\"]}\n", "structuredPatch": [], "originalFile": null, "userModified": false}{
"command": "python -m pytest -rA 2>&1 | tail -25",
"description": "Run full test suite"
}PASSED test/test_wsgi.py::TestRouteDecorator::test_after_request_sees_HTTPError_response
PASSED test/test_wsgi.py::TestRouteDecorator::test_after_response_hook_can_set_headers
PASSED test/test_wsgi.py::TestRouteDecorator::test_apply
PASSED test/test_wsgi.py::TestRouteDecorator::test_apply_list
PASSED test/test_wsgi.py::TestRouteDecorator::test_callback
PASSED test/test_wsgi.py::TestRouteDecorator::test_decorators
PASSED test/test_wsgi.py::TestRouteDecorator::test_hooks
PASSED test/test_wsgi.py::TestRouteDecorator::test_method
PASSED test/test_wsgi.py::TestRouteDecorator::test_method_list
PASSED test/test_wsgi.py::TestRouteDecorator::test_name
PASSED test/test_wsgi.py::TestRouteDecorator::test_no_params_at_all
PASSED test/test_wsgi.py::TestRouteDecorator::test_no_path
PASSED test/test_wsgi.py::TestRouteDecorator::test_path_list
PASSED test/test_wsgi.py::TestRouteDecorator::test_single_path
PASSED test/test_wsgi.py::TestRouteDecorator::test_template
PASSED test/test_wsgi.py::TestRouteDecorator::test_template_opts
PASSED test/test_wsgi.py::TestDecorators::test_autoroute
PASSED test/test_wsgi.py::TestDecorators::test_routebuild
PASSED test/test_wsgi.py::TestDecorators::test_truncate_body
PASSED test/test_wsgi.py::TestDecorators::test_view
PASSED test/test_wsgi.py::TestDecorators::test_view_error
PASSED test/test_wsgi.py::TestAppShortcuts::testWithStatement
PASSED test/test_wsgi.py::TestAppShortcuts::test_module_shortcuts
PASSED test/test_wsgi.py::TestAppShortcuts::test_module_shortcuts_with_different_name
============================= 367 passed in 0.58s ==============================
[stdout]
PASSED test/test_wsgi.py::TestRouteDecorator::test_after_request_sees_HTTPError_response
PASSED test/test_wsgi.py::TestRouteDecorator::test_after_response_hook_can_set_headers
PASSED test/test_wsgi.py::TestRouteDecorator::test_apply
PASSED test/test_wsgi.py::TestRouteDecorator::test_apply_list
PASSED test/test_wsgi.py::TestRouteDecorator::test_callback
PASSED test/test_wsgi.py::TestRouteDecorator::test_decorators
PASSED test/test_wsgi.py::TestRouteDecorator::test_hooks
PASSED test/test_wsgi.py::TestRouteDecorator::test_method
PASSED test/test_wsgi.py::TestRouteDecorator::test_method_list
PASSED test/test_wsgi.py::TestRouteDecorator::test_name
PASSED test/test_wsgi.py::TestRouteDecorator::test_no_params_at_all
PASSED test/test_wsgi.py::TestRouteDecorator::test_no_path
PASSED test/test_wsgi.py::TestRouteDecorator::test_path_list
PASSED test/test_wsgi.py::TestRouteDecorator::test_single_path
PASSED test/test_wsgi.py::TestRouteDecorator::test_template
PASSED test/test_wsgi.py::TestRouteDecorator::test_template_opts
PASSED test/test_wsgi.py::TestDecorators::test_autoroute
PASSED test/test_wsgi.py::TestDecorators::test_routebuild
PASSED test/test_wsgi.py::TestDecorators::test_truncate_body
PASSED test/test_wsgi.py::TestDecorators::test_view
PASSED test/test_wsgi.py::TestDecorators::test_view_error
PASSED test/test_wsgi.py::TestAppShortcuts::testWithStatement
PASSED test/test_wsgi.py::TestAppShortcuts::test_module_shortcuts
PASSED test/test_wsgi.py::TestAppShortcuts::test_module_shortcuts_with_different_name
============================= 367 passed in 0.58s ==============================
[metadata] {"noOutputExpected": false}{
"command": "python -c \"\nimport bottle\nr = bottle.BaseResponse()\nfor name, val in [('X-Test','ok\\r\\nSet-Cookie: evil=1'), ('X-Bad\\nInjected','v'), ('X-Nul','a\\0b')]:\n try:\n r.set_header(name, val); print('NOT BLOCKED:', repr(name), repr(val))\n except ValueError as e:\n print('ValueError:', e)\n# sanity: normal headers still work\nr.set_header('Content-Type', 'text/plain'); r.add_header('X-A', 'b')\nprint('ok ->', r['Content-Type'], r['X-A'])\n# redirect with a tainted location is now rejected rather than splitting the response\ntry:\n bottle.redirect('/next\\r\\nX-Injected: 1')\nexcept ValueError as e:\n print('redirect ValueError:', e)\nexcept bottle.HTTPResponse:\n print('NOT BLOCKED: redirect')\n\"",
"description": "Verify injection is blocked and normal headers work"
}ValueError: Header value must not contain control characters: 'ok\r\nSet-Cookie: evil=1'
ValueError: Header names must not contain control characters: 'X-Bad\nInjected'
ValueError: Header value must not contain control characters: 'a\x00b'
ok -> text/plain b
NOT BLOCKED: redirect
[stdout]
ValueError: Header value must not contain control characters: 'ok\r\nSet-Cookie: evil=1'
ValueError: Header names must not contain control characters: 'X-Bad\nInjected'
ValueError: Header value must not contain control characters: 'a\x00b'
ok -> text/plain b
NOT BLOCKED: redirect
[metadata] {"noOutputExpected": false}{
"command": "git diff && echo \"--- report ---\" && cat report.jsonl",
"description": "Show final diff and report"
}--- report ---
{"file_path": "/app/bottle.py", "cwe_id": ["cwe-93", "cwe-113", "cwe-20"]}
[stdout]
--- report ---
{"file_path": "/app/bottle.py", "cwe_id": ["cwe-93", "cwe-113", "cwe-20"]}
[metadata] {"noOutputExpected": false}{
"command": "grep -n \"def redirect\" -A 12 /app/bottle.py",
"description": "Inspect redirect implementation"
}2716:def redirect(url, code=None):
2717- """ Aborts execution and causes a 303 or 302 redirect, depending on
2718- the HTTP protocol version. """
2719- if not code:
2720- code = 303 if request.get('SERVER_PROTOCOL') == "HTTP/1.1" else 302
2721- res = response.copy(cls=HTTPResponse)
2722- res.status = code
2723- res.body = ""
2724- res.set_header('Location', urljoin(request.url, url))
2725- raise res
2726-
2727-
2728-def _rangeiter(fp, offset, limit, bufsize=1024 * 1024):
[stdout]
2716:def redirect(url, code=None):
2717- """ Aborts execution and causes a 303 or 302 redirect, depending on
2718- the HTTP protocol version. """
2719- if not code:
2720- code = 303 if request.get('SERVER_PROTOCOL') == "HTTP/1.1" else 302
2721- res = response.copy(cls=HTTPResponse)
2722- res.status = code
2723- res.body = ""
2724- res.set_header('Location', urljoin(request.url, url))
2725- raise res
2726-
2727-
2728-def _rangeiter(fp, offset, limit, bufsize=1024 * 1024):
[metadata] {"noOutputExpected": false}{
"command": "python -c \"\nfrom bottle import request\ntry:\n from urllib.parse import urljoin\nexcept ImportError:\n from urlparse import urljoin\nprint(repr(urljoin('http://localhost/', '/next\\r\\nX-Injected: 1')))\n\"",
"description": "Check whether urljoin strips CRLF"
}'http://localhost/nextX-Injected: 1'
[stdout]
'http://localhost/nextX-Injected: 1'
[metadata] {"noOutputExpected": false}