From e8c6f9db6b7a2e25bada02256d4e281ad7322166 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:14:38 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20?= =?UTF-8?q?=EB=B9=84=20ASCII=20=EB=AC=B8=EC=9E=90=EB=A5=BC=20=ED=86=B5?= =?UTF-8?q?=ED=95=9C=20hmac.compare=5Fdigest=20DoS=20=EC=B7=A8=EC=95=BD?= =?UTF-8?q?=EC=A0=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/sentinel.md | 4 ++++ saas_web.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 858d9d42..69063be9 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -60,3 +60,7 @@ **Vulnerability:** Path traversal in `media_shrinker.py` via unresolved `..` segments or symlink escapes before deriving conversion output paths. **Learning:** `Path.relative_to()` is only a lexical containment check unless both the source and root have first been resolved into canonical absolute paths. Relative paths and symlinks can otherwise bypass root-boundary assumptions. **Prevention:** Resolve both source and root once, reject sources outside the resolved root with a sanitized `MediaShrinkerError`, and derive `rel_source` from the resolved paths before planning outputs. +## 2024-05-18 - hmac.compare_digest 비 ASCII 문자 처리 취약점 +**취약점:** `hmac.compare_digest()`에 비 ASCII 문자가 포함된 문자열을 전달하면 `TypeError`가 발생하여 500 서버 오류를 유발하고 DoS 공격에 노출될 수 있음. +**학습:** FastAPI의 테스트 클라이언트나 httpx 등은 비 ASCII 헤더를 차단하지만, 실제 환경에서는 악의적인 클라이언트가 이를 우회하여 전송할 수 있음. +**예방:** `hmac.compare_digest()`를 호출하기 전에 항상 두 인자를 명시적으로 바이트(`.encode('utf-8')`)로 인코딩하여 비교해야 함. diff --git a/saas_web.py b/saas_web.py index 3a7b0352..a5e6fc5b 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,