From 57a28c602e67072f8bce99380ba42ec63d3ecad1 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 28 Aug 2026 21:18:58 +0000 Subject: [PATCH 1/7] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20hmac.compare=5Fdigest=EC=9D=98=20=EB=B9=84-ASCII=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?(500=20=EC=97=90=EB=9F=AC)=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hmac.compare_digest 함수는 ASCII 범위 외의 문자열이 주어졌을 때 TypeError를 발생시키며, 이로 인해 사용자가 X-API-Key 헤더에 비-ASCII 문자를 전송하면 500 에러가 반환되어 DoS 공격의 원인이 될 수 있습니다. 이 커밋은 두 입력 문자열을 모두 utf-8 바이트로 인코딩한 뒤에 hmac.compare_digest를 호출하도록 개선하여 오류를 방지하고 정상적으로 401 Unauthorized를 반환하도록 수정합니다. 관련 단위 테스트도 추가되었습니다. --- .jules/sentinel.md | 5 +++++ saas_web.py | 2 +- tests/test_saas_web.py | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 9c9d083b..a8376676 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -1,3 +1,8 @@ +## 2026-08-28 - [Sentinel: Unhandled hmac.compare_digest TypeError (DoS)] +**취약점:** `hmac.compare_digest`에서 발생한 예외가 처리되지 않아 500 Internal Server Error를 유발하고, 이를 통한 서비스 거부(DoS) 공격이 가능함 (CWE-400). +**학습 내용:** Python의 `hmac.compare_digest`는 ASCII 문자가 아닌 문자가 포함된 문자열을 비교할 때 `TypeError`를 발생시킴. 악의적인 사용자가 X-API-Key 헤더에 비-ASCII 문자를 전송하면 401 에러 대신 애플리케이션의 에러율을 높여 서버 장애를 일으킬 수 있음. +**예방 조치:** 모든 API 키 문자열 입력을 `utf-8` 바이트로 인코딩한 후 `hmac.compare_digest`로 전달하여 안전하게 비교를 수행하도록 함. + ## 2026-07-25 - [Cross-platform upload basename normalization] **Behavior:** Upload metadata now interprets both forward slashes and backslashes as path separators before extracting a basename. **Learning:** On POSIX systems, `pathlib.Path(filename).name` retains backslashes because they are ordinary characters there. That caused inconsistent manifest and converter filenames for Windows-style client paths. The upload itself is still written inside a trusted temporary workspace, and batch archive entry names are generated outputs; this change does not establish a filesystem traversal or archive-entry escape. diff --git a/saas_web.py b/saas_web.py index 63265e94..071b1419 100644 --- a/saas_web.py +++ b/saas_web.py @@ -114,7 +114,7 @@ async def require_api_key(request: Request, call_next): if configured_keys and not (request.method == "GET" and request.url.path == "/"): provided_key = request.headers.get("x-api-key", "") if not any( - hmac.compare_digest(provided_key, key) for key in configured_keys + hmac.compare_digest(provided_key.encode("utf-8"), key.encode("utf-8")) for key in configured_keys ): return JSONResponse( status_code=401, diff --git a/tests/test_saas_web.py b/tests/test_saas_web.py index 3b57e033..d06f9a96 100644 --- a/tests/test_saas_web.py +++ b/tests/test_saas_web.py @@ -1222,6 +1222,13 @@ def test_video_content_type_accepted_by_validator(self): ) ) + @patch.dict(os.environ, {"CODEC_CARVER_API_KEYS": "secret1,secret2"}, clear=True) + def test_hmac_non_ascii_api_key_401(self): + # Pass headers as bytes to bypass httpx's strict ASCII string check. + response = client.get("/jobs/123", headers={b"X-API-Key": "test🌟".encode("utf-8")}) + self.assertEqual(response.status_code, 401) + self.assertEqual(response.json(), {"error": "Invalid or missing API key"}) + if __name__ == "__main__": unittest.main() From b0817954bb19a989de89b11812000c2cc78a9db8 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 28 Aug 2026 21:34:53 +0000 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20hmac.compare=5Fdigest=EC=9D=98=20=EB=B9=84-ASCII=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?(500=20=EC=97=90=EB=9F=AC)=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hmac.compare_digest 함수는 ASCII 범위 외의 문자열이 주어졌을 때 TypeError를 발생시키며, 이로 인해 사용자가 X-API-Key 헤더에 비-ASCII 문자를 전송하면 500 에러가 반환되어 DoS 공격의 원인이 될 수 있습니다. 이 커밋은 두 입력 문자열을 모두 utf-8 바이트로 인코딩한 뒤에 hmac.compare_digest를 호출하도록 개선하여 오류를 방지하고 정상적으로 401 Unauthorized를 반환하도록 수정합니다. 관련 단위 테스트도 추가되었습니다. From bf4d7888ed3201333583ba801d56aa3159e17789 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 28 Aug 2026 21:38:30 +0000 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20hmac.compare=5Fdigest=EC=9D=98=20=EB=B9=84-ASCII=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?(500=20=EC=97=90=EB=9F=AC)=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hmac.compare_digest 함수는 ASCII 범위 외의 문자열이 주어졌을 때 TypeError를 발생시키며, 이로 인해 사용자가 X-API-Key 헤더에 비-ASCII 문자를 전송하면 500 에러가 반환되어 DoS 공격의 원인이 될 수 있습니다. 이 커밋은 두 입력 문자열을 모두 utf-8 바이트로 인코딩한 뒤에 hmac.compare_digest를 호출하도록 개선하여 오류를 방지하고 정상적으로 401 Unauthorized를 반환하도록 수정합니다. 관련 단위 테스트도 추가되었습니다. From 9a1858d297538e844ad2f5126030ae224ae48a63 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 28 Aug 2026 21:48:22 +0000 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20hmac.compare=5Fdigest=EC=9D=98=20=EB=B9=84-ASCII=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?(500=20=EC=97=90=EB=9F=AC)=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hmac.compare_digest 함수는 ASCII 범위 외의 문자열이 주어졌을 때 TypeError를 발생시키며, 이로 인해 사용자가 X-API-Key 헤더에 비-ASCII 문자를 전송하면 500 에러가 반환되어 DoS 공격의 원인이 될 수 있습니다. 이 커밋은 두 입력 문자열을 모두 utf-8 바이트로 인코딩한 뒤에 hmac.compare_digest를 호출하도록 개선하여 오류를 방지하고 정상적으로 401 Unauthorized를 반환하도록 수정합니다. 관련 단위 테스트도 추가되었습니다. From e7fa66d578142f6ccbd76d36b590de3f90e8f992 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 28 Aug 2026 22:04:41 +0000 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20hmac.compare=5Fdigest=EC=9D=98=20=EB=B9=84-ASCII=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?(500=20=EC=97=90=EB=9F=AC)=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hmac.compare_digest 함수는 ASCII 범위 외의 문자열이 주어졌을 때 TypeError를 발생시키며, 이로 인해 사용자가 X-API-Key 헤더에 비-ASCII 문자를 전송하면 500 에러가 반환되어 DoS 공격의 원인이 될 수 있습니다. 이 커밋은 두 입력 문자열을 모두 utf-8 바이트로 인코딩한 뒤에 hmac.compare_digest를 호출하도록 개선하여 오류를 방지하고 정상적으로 401 Unauthorized를 반환하도록 수정합니다. 관련 단위 테스트도 추가되었습니다. From c3b2814a27e72eb65e5223374ac346ffb713464a Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 28 Aug 2026 22:30:57 +0000 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20hmac.compare=5Fdigest=EC=9D=98=20=EB=B9=84-ASCII=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?(500=20=EC=97=90=EB=9F=AC)=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hmac.compare_digest 함수는 ASCII 범위 외의 문자열이 주어졌을 때 TypeError를 발생시키며, 이로 인해 사용자가 X-API-Key 헤더에 비-ASCII 문자를 전송하면 500 에러가 반환되어 DoS 공격의 원인이 될 수 있습니다. 이 커밋은 두 입력 문자열을 모두 utf-8 바이트로 인코딩한 뒤에 hmac.compare_digest를 호출하도록 개선하여 오류를 방지하고 정상적으로 401 Unauthorized를 반환하도록 수정합니다. 관련 단위 테스트도 추가되었습니다. From cbc5b2d386ca24049116ff3871134681d8a404ca Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 28 Aug 2026 22:55:42 +0000 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20hmac.compare=5Fdigest=EC=9D=98=20=EB=B9=84-ASCII=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?(500=20=EC=97=90=EB=9F=AC)=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hmac.compare_digest 함수는 ASCII 범위 외의 문자열이 주어졌을 때 TypeError를 발생시키며, 이로 인해 사용자가 X-API-Key 헤더에 비-ASCII 문자를 전송하면 500 에러가 반환되어 DoS 공격의 원인이 될 수 있습니다. 이 커밋은 두 입력 문자열을 모두 utf-8 바이트로 인코딩한 뒤에 hmac.compare_digest를 호출하도록 개선하여 오류를 방지하고 정상적으로 401 Unauthorized를 반환하도록 수정합니다. 관련 단위 테스트도 추가되었습니다.