andrewmusselman opened a new issue, #712:
URL: https://github.com/apache/tooling-trusted-releases/issues/712
**ASVS Requirement:** 4.1.1 — Verify that every HTTP response with a message
body contains a Content-Type header field that matches the actual content,
including the charset parameter
**Severity:** Low
**CWE:** CWE-436 (Interpretation Conflict)
### Description
Several endpoints and response helper classes set `mimetype` without an
explicit `charset` parameter. While werkzeug may implicitly append
`charset=utf-8` for `text/*` types, it does not do so for `application/json`.
ASVS 4.1.1 requires charset to be explicitly specified.
### Affected Locations
**1. `atr/get/root.py` (lines 118–122)** — `/miscellaneous/resolved.json`
endpoint:
```python
return quart_response.Response(content, mimetype="application/json") # No
charset
```
**2. `atr/post/upload.py` (lines 168–173)** — `_json_error` and
`_json_success` helpers:
```python
def _json_error(message: str, status: int) -> web.WerkzeugResponse:
return response.Response(json.dumps({"error": message}), status=status,
mimetype="application/json")
def _json_success(data: dict[str, str], status: int = 200) ->
web.WerkzeugResponse:
return response.Response(json.dumps(data), status=status,
mimetype="application/json")
```
**3. `atr/web.py` (lines 211–259)** — Custom response classes
(`ElementResponse`, `ShellResponse`, `TextResponse`) use `mimetype` without
explicit charset:
```python
class TextResponse(quart.Response):
def __init__(self, text: str, status: int = 200) -> None:
super().__init__(text, status=status, mimetype="text/plain")
```
**4. `atr/post/tokens.py` (lines 53–56)** — JWT endpoint returns a token as
`TextResponse`; the more specific `application/jwt` media type would be
appropriate.
### Recommended Fix
Use `content_type` instead of `mimetype` to include charset in all cases:
```python
# JSON helpers
return response.Response(
json.dumps({"error": message}),
status=status,
content_type="application/json; charset=utf-8"
)
# Custom response classes
class TextResponse(quart.Response):
def __init__(self, text: str, status: int = 200) -> None:
super().__init__(text, status=status, content_type="text/plain;
charset=utf-8")
# JWT endpoint (optional improvement)
return quart.Response(jwt_token, content_type="application/jwt;
charset=utf-8")
```
Consider also adding an `after_request` handler as defense-in-depth to catch
any future omissions:
```python
@app.after_request
async def ensure_charset(response):
if response.content_type and "charset" not in response.content_type:
if response.content_type.startswith("text/"):
response.content_type = f"{response.content_type}; charset=utf-8"
return response
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]