From 9037edd315ee6f7c9d3db12da13090b5981902d3 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 9 Sep 2026 21:05:02 +0000 Subject: [PATCH] =?UTF-8?q?=EB=B3=B4=EC=95=88=20=EC=88=98=EC=A0=95:=20?= =?UTF-8?q?=EC=9D=B4=EC=A4=91=20=ED=99=95=EC=9E=A5=EC=9E=90=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=9A=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=B7=A8=EC=95=BD=EC=A0=90=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit backend/services/email_import_service.py의 canonical_email_import_upload_filename 함수에 이중 확장자(예: malicious.exe.eml) 검증 로직을 추가했습니다. 파일 이름의 중간에 위험한 확장자(.exe, .sh, .bat, .cmd, .vbs, .ps1)가 포함된 경우 업로드를 차단합니다. .com과 .js는 정상적인 파일 이름(예: 이메일 주소 포함)에 자주 사용되므로 검증 목록에서 제외했습니다. 관련 테스트 케이스와 CHANGELOG.md 업데이트도 포함되었습니다. --- CHANGELOG.md | 1 + backend/services/email_import_service.py | 9 +++++++++ backend/tests/test_email_import_service.py | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ec84c36f..e3b0cc98d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2737,6 +2737,7 @@ ## [Unreleased] ### Added +- **보안 수정(Security Fix):** `backend/services/email_import_service.py`의 `canonical_email_import_upload_filename` 함수에서 이중 확장자(double extension) 공격(예: `malicious.exe.eml`)을 차단할 수 있도록 검증 로직을 추가했습니다. - `backend/api/tools.py` 내의 임시 `mock_handler`를 구체적인 기능을 수행하는 5개의 실제 도구 핸들러로 대체했습니다. - `thread_summarizer_handler`: 이메일 스레드 요약 정보 반환 - `action_item_extractor_handler`: 실행 항목 및 마감일 추출 diff --git a/backend/services/email_import_service.py b/backend/services/email_import_service.py index ddfa350fd..a2f6a464b 100644 --- a/backend/services/email_import_service.py +++ b/backend/services/email_import_service.py @@ -158,6 +158,15 @@ def canonical_email_import_upload_filename(filename: str | None) -> str | None: or Path(canonical_name).suffix.lower() not in SUPPORTED_EMAIL_IMPORT_SUFFIXES ): return None + + # Reject files with embedded dangerous extensions (e.g. malicious.exe.eml) + # Exclude .com and .js as they can be part of valid email addresses or filenames + dangerous_extensions = {".exe", ".sh", ".bat", ".cmd", ".vbs", ".ps1"} + parts = canonical_name.split(".") + for part in parts: + if f".{part.lower()}" in dangerous_extensions: + return None + return canonical_name diff --git a/backend/tests/test_email_import_service.py b/backend/tests/test_email_import_service.py index 51d2a2633..1b04d3bea 100644 --- a/backend/tests/test_email_import_service.py +++ b/backend/tests/test_email_import_service.py @@ -68,6 +68,11 @@ def test_safe_upload_filename_fails_closed_beyond_decode_round_limit(): ("%0amessage.eml", None), ("secret.eml%00.zip", None), ("payload.exe", None), + ("malicious.exe.eml", None), + ("malicious.sh.eml", None), + ("malicious.bat.eml", None), + ("sender@example.com.eml", "sender@example.com.eml"), + ("vue.js_newsletter.eml", "vue.js_newsletter.eml"), ], ) def test_canonical_email_import_upload_filename(input_name, expected):