🔐로그인하면 문서 작성, 프로젝트 게시, ZIP 기반 버전 업로드, 브랜치 생성 기능을 사용할 수 있습니다. 로그인하러 가기
비교 대상 선택
추가 0줄 삭제 0줄 변경 0줄 동일 386줄
r1 최초 작성
2026-04-22 15:20

T2Editor 9.1.1 전수감사 보고서

#감사 #T2Editor

문서 성격

본 문서는 T2Editor 9.1.1 패키지 전체를 대상으로 수행한 전수감사 보고서이다. 감사 범위는 패키지 내 전체 69개 파일이며, 1차 자산 인벤토리 작성, 2차 정적 구조 검토, 3차 위험 패턴 점검, 4차 문법 검사 및 대표 행위 스팟 테스트 순으로 수행하였다.

1. 감사 개요

항목내용
대상 버전T2Editor 9.1.1
기준 자료패키지 원본 /t2editor 디렉터리 전체
조사 방식전수조사·전수감사
조사 대상 수총 69개 파일
파일 구성PHP 13, JS 26, CSS 16, 기타 자산 14
감사 관점서버측 입력검증, 출력안전성, 업로드 경계, 협업 엔드포인트, 클라이언트 런타임, 외부 의존성, 운영 호환성
감사 결과'''외부 공개 서비스 기준 조건부 부적정'''

2. 감사 방법

2.1 조사 절차

  1. 패키지 전체 파일 인벤토리 작성
  2. 기능군별 분류
  • 부트스트랩/설정
  • 코어 에디터 런타임
  • 업로드/뷰어
  • 협업 플러그인
  • 파일/이미지/비디오/표/코드 플러그인
  • 외부 서비스 연계 플러그인
  • 번들·폰트·정적 자산
  1. PHP 파일 문법 검사 수행
  2. 위험 패턴 탐지
  • innerHTML, execCommand, DOMNodeInserted, HTTP_HOST, Access-Control-Allow-Origin: *, move_uploaded_file, flock, chmod, localStorage
  1. 대표 경로 스팟 테스트
  • t2_config.php Host Header 반영 여부
  • upload_config.php 파일 검증 함수 동작 여부

2.2 감사 기준

  • 입력값이 검증 없이 파일시스템, HTML, JS, URL 문맥에 사용되는지 여부
  • 업로드 엔드포인트가 확장자 외의 실질 검증을 수행하는지 여부
  • 뷰어/미리보기 경로가 외부 URL, 상대경로, 임의 속성 삽입에 대해 안전한지 여부
  • 클라이언트 측 sanitizer가 허용 태그·속성·프로토콜을 충분히 제한하는지 여부
  • 보조 엔드포인트가 과도한 CORS, 과도한 권한, 파일명 불일치, 정리 누락을 갖는지 여부
  • 운영 환경 변수(HTTP_HOST, DOCUMENT_ROOT, Origin)를 신뢰해도 되는 방식으로 사용하는지 여부

3. 자산 현황

3.1 기능군별 구성

기능군주요 파일감사 관찰
부트스트랩·설정editor.lib.php, config/t2_config.php, config/upload_config.php, config/get_upload_config.php에디터 HTML/JS 부트스트랩, 경로 계산, 업로드 정책, 설정 노출
코어 런타임js/core.js, js/toolbar.js, js/utils.js편집 동작, 붙여넣기, 히스토리, autosave, sanitizer, 플러그인 로드
업로드·뷰어plugin/file/file_upload.php, plugin/image/image_upload.php, plugin/file/pdf_view.php, plugin/video/video_view.php파일 저장, 이미지 처리, PDF/비디오 표시
협업plugin/collab/*.php, plugin/collab/collab.js룸 생성, 입장/퇴장, 편집 상태 파일 저장, 정리
핵심 플러그인plugin/file, plugin/image, plugin/video, plugin/table, plugin/code파일 블럭, 이미지, 비디오, 테이블, 코드 블럭
외부 서비스 연계plugin/ai, plugin/ai_rearrange, plugin/clipurl, plugin/search, plugin/meme외부 API 및 웹 자산 의존
번들·정적 자산vendor/*, js/pdf*.js, fonts/*배포 번들, 모델 파일, 폰트

3.2 전수조사 대상 파일 목록

파일 목록 보기
  • config/get_upload_config.php
  • config/nsfw_api_browser.js
  • config/t2_config.php
  • config/upload_config.php
  • css/content.css
  • css/core.css
  • css/dark.css
  • editor.lib.php
  • fonts/material-icons/MaterialIcons-Regular.eot
  • fonts/material-icons/MaterialIcons-Regular.ttf
  • fonts/material-icons/MaterialIcons-Regular.woff
  • fonts/material-icons/MaterialIcons-Regular.woff2
  • fonts/material-icons/MaterialIconsOutlined-Regular.woff2
  • fonts/material-icons/font.woff2
  • js/core.js
  • js/jszip.min.js
  • js/pdf.min.js
  • js/pdf.worker.min.js
  • js/toolbar.js
  • js/utils.js
  • plugin/ai/ai.css
  • plugin/ai/ai.js
  • plugin/ai_rearrange/ai_rearrange.css
  • plugin/ai_rearrange/ai_rearrange.js
  • plugin/clipurl/clipurl.css
  • plugin/clipurl/clipurl.js
  • plugin/code/code.css
  • plugin/code/code.js
  • plugin/collab/collab.css
  • plugin/collab/collab.js
  • plugin/collab/collab_number.php
  • plugin/collab/collab_number_delete.php
  • plugin/collab/collab_verification.php
  • plugin/draw/draw.css
  • plugin/draw/draw.js
  • plugin/export/export.js
  • plugin/export/export_html_skin.html
  • plugin/file/file.css
  • plugin/file/file.js
  • plugin/file/file_upload.php
  • plugin/file/pdf_view.php
  • plugin/image/image.css
  • plugin/image/image.js
  • plugin/image/image_upload.php
  • plugin/link/link.css
  • plugin/link/link.js
  • plugin/meme/meme.css
  • plugin/meme/meme.js
  • plugin/search/search.css
  • plugin/search/search.js
  • plugin/table/table.css
  • plugin/table/table.js
  • plugin/video/video.css
  • plugin/video/video.js
  • plugin/video/video_view.php
  • readme.txt
  • t2_css_min.php
  • t2_js_min.php
  • vendor/nsfwjs/models/mobilenet_v2_mid/group1-shard1of2
  • vendor/nsfwjs/models/mobilenet_v2_mid/group1-shard2of2
  • vendor/nsfwjs/models/mobilenet_v2_mid/model.json
  • vendor/nsfwjs/nsfwjs.min.js
  • vendor/tfjs-backend-wasm/tf-backend-wasm.min.js
  • vendor/tfjs-backend-wasm/tfjs-backend-wasm-simd.wasm
  • vendor/tfjs-backend-wasm/tfjs-backend-wasm-threaded-simd.wasm
  • vendor/tfjs-backend-wasm/tfjs-backend-wasm.wasm
  • vendor/tfjs-backend-webgl/tf-backend-webgl.min.js
  • vendor/tfjs-backend-webgpu/tf-backend-webgpu.min.js
  • vendor/tfjs/tf.min.js

4. 총괄 판단

총평

T2Editor 9.1.1은 편집기 기능 범위가 넓고 플러그인 구조도 비교적 정돈되어 있다. 다만 보안 관점에서 보면 서버측 검증 경계가 얕고, 클라이언트 측 HTML 재구성 경로가 공격면을 크게 노출하며, 업로드·비디오·협업 보조 엔드포인트에 다수의 구조적 취약점이 존재한다. 특히 editor.lib.php, js/core.js, plugin/video/video_view.php, plugin/file/file_upload.php, plugin/image/image_upload.php는 우선 보완 대상이다.

4.1 종합 판정

구분판정의견
기능 완성도양호플러그인 수와 사용성은 충분함
서버측 입력검증미흡확장자·크기 중심 검증, URL·Host·Origin 통제 부족
출력 안전성미흡raw textarea, JS 문자열, innerHTML 재구성 경로 다수
업로드 경계미흡MIME/매직바이트 검증 부재, 이미지 자원 제한 부재
협업 보조 엔드포인트주의파일권한·CORS·정리 로직 불일치 존재
운영 호환성보통경로 자동 계산은 있으나 Host 신뢰가 과도함
외부 공개 서비스 적합성'''조건부 부적정'''보안 선행 보완 없이는 공개 운영 비권고

5. 주요 강점

  • 전체 PHP 파일 13개에 대해 문법 오류가 확인되지 않았다.
  • 이미지 업로드 경로에서 getimagesize() 기반 실제 이미지 여부 확인은 수행한다.
  • 협업 기능은 flock() 기반 잠금과 원자적 JSON 업데이트 구조를 일부 도입하고 있다.
  • PDF 뷰어와 코드 블럭, 테이블, 파일 블럭 등 기능 모듈화는 비교적 명확하다.
  • 라이선스/버전 정보와 기본 플러그인 우선순위 관리 구조는 일관적이다.

6. 세부 감사 결과

6.1 Critical

식별자위험도위치판정요약
F-01Criticaleditor.lib.php미조치본문 내용과 ID 값이 HTML/JS 문맥에 직접 삽입되어 구조 파손 및 XSS 가능성이 존재함
F-02Criticaljs/core.js미조치붙여넣기 및 sanitizer가 innerHTML과 얕은 allowlist에 의존하여 DOM XSS 우회 가능성이 큼

F-01. 본문 로딩/저장 경계의 직접 출력

  • editor.lib.php:289-295에서 본문을 JS 문자열로 가공하나 </script> 조기 종료와 컨텍스트 분리가 충분하지 않다.
  • editor.lib.php:494-495에서 hidden textarea에 $id, $content를 그대로 출력한다.
  • editor.lib.php:528-535에서 window.<id>_editortempDiv.innerHTML = contentToLoad를 직접 수행한다.
  • editor.lib.php:584에서도 일반 textarea 경로에 본문을 그대로 출력한다.
  • editor.lib.php:595-597에서 저장 직전 다시 innerHTML 재구성을 수행한다.

'''감사의견'''
본문 또는 필드 ID가 신뢰되지 않는 경로에서 유입될 경우 DOM 파손, 스크립트 블록 조기 종료, HTML 속성 탈출, 저장 시 이차적 구조 오염으로 이어질 수 있다. 본 항목은 패키지의 핵심 출력 경계에 해당하므로 우선순위가 가장 높다.

F-02. 코어 sanitizer 및 붙여넣기 경계의 구조적 취약

  • js/core.js:493-517에서 붙여넣기 내용을 tempDiv.innerHTML로 해석한 후 currentBlock.innerHTML = beforeText + sanitizedHTML + afterText 방식으로 다시 삽입한다.
  • js/core.js:2078-2103sanitizeHTML()href, src, style을 허용하면서 프로토콜 및 스타일 값 검증을 하지 않는다.
  • allowedTags에는 a, img, span, div 등이 포함되어 있어 속성 조합 우회 가능성이 존재한다.

'''감사의견'''
전형적인 “수제 sanitizer” 구조이며, 프로토콜·CSS·이벤트 간접 주입을 방어하기에 부족하다. 특히 붙여넣기 경계는 외부 HTML이 대량 유입되는 지점이므로, 실제 서비스 환경에서는 DOMPurify급 검증기로 교체하는 편이 타당하다.

6.2 High

식별자위험도위치판정요약
F-03Highplugin/video/video_view.php미조치외부 URL 및 상대경로를 충분히 제한하지 않아 비디오 뷰어가 비허용 URL을 그대로 렌더링할 수 있음
F-04Highconfig/upload_config.php, plugin/file/file_upload.php, plugin/image/image_upload.php미조치업로드 검증이 실질적으로 확장자·크기 중심이며 MIME/매직바이트 검증이 없음
F-05Highplugin/file/file.js, plugin/video/video.js, plugin/table/table.js미조치파일명/URL/클립보드 HTML이 innerHTML로 재삽입되어 XSS 공격면이 존재함
F-06Highconfig/t2_config.php미조치HTTP_HOST를 검증 없이 신뢰하여 URL 계산에 사용함
F-07Highplugin/image/image_upload.php미조치무제한 메모리/실행시간 설정으로 자원 고갈 위험이 큼

F-03. 비디오 뷰어의 외부 URL 통과 및 경로 검증 부재

  • plugin/video/video_view.php:8-19에서 $_GET['video']를 받아 http로 시작하지 않으면 절대경로로 변환한다.
  • 즉, http://, https:// 형태의 외부 URL은 그대로 통과한다.
  • plugin/video/video_view.php:24-26은 확장자만 확인하고, 실제 허용 도메인 또는 데이터 디렉터리 하위 여부를 검증하지 않는다.

'''감사의견'''
브라우저 기준의 외부 요청 유발, 핫링킹, 예기치 않은 제3자 호스트 렌더링, 상대경로 오염 가능성이 있다. 비디오 뷰어는 same-origin 또는 명시적 allowlist 기반으로 제한해야 한다.

F-04. 업로드 경계의 실질 검증 부재

  • config/upload_config.php:138-156validate_upload_file()는 확장자와 파일 크기만 검사한다.
  • plugin/file/file_upload.php:47-50은 해당 함수를 그대로 사용한다.
  • plugin/image/image_upload.php:72-76 역시 같은 함수를 호출하나, 본질적으로 확장자·크기 확인에 머문다.
  • 스팟 테스트 결과 validate_upload_file('fake.mp4', 100, 'video')는 성공을 반환하였다.

'''감사의견'''
현재 구조는 위장 확장자, 내용 불일치 파일, 악성 샘플에 취약하다. 최소한 MIME, 매직바이트, 이미지 픽셀 한도, 업로드 실패 원인 세분화가 필요하다.

F-05. 플러그인별 HTML 재삽입 경계

  • plugin/file/file.js:683-729fileInfo.url, fileInfo.original_name을 오디오/일반 파일 블럭 innerHTML에 직접 삽입한다.
  • plugin/video/video.js:269-279은 업로드 후 미리보기에서 data.file.url, file.name을 그대로 사용한다.
  • plugin/video/video.js:561-565는 URL 수정 모달의 value="${currentUrl}"에 현재 URL을 그대로 넣는다.
  • plugin/table/table.js:20-26은 클립보드 HTML에서 tablecloneNode(true)로 복사하나, 이벤트 속성 제거가 없다.

'''감사의견'''
서버 응답, 파일명, 클립보드 HTML을 신뢰하는 구조다. 업로드 응답이 오염되거나 사용자가 악성 파일명·테이블 HTML을 다루는 환경에서는 DOM XSS가 가능하다.

F-06. Host Header 신뢰

  • config/t2_config.php:25-35에서 $_SERVER['HTTP_HOST']를 그대로 T2EDITOR_URL 계산에 사용한다.
  • 스팟 테스트 결과 악성 Host 문자열이 URL 상수에 그대로 반영되었다.

'''감사의견'''
역프록시 설정이 약하거나 Host 헤더 검증이 없는 배포 환경에서는 링크·리소스 경로 위변조가 가능하다. Host는 allowlist 또는 정규식 검증 후 사용해야 한다.

F-07. 이미지 처리 자원 한도 부재

  • plugin/image/image_upload.php:8-9에서 memory_limit = -1, max_execution_time = 0을 설정한다.
  • 이미지 크기·픽셀 수·예상 메모리 사용량을 제한하지 않는다.

'''감사의견'''
고해상도 이미지, 손상된 이미지, 압축폭탄 계열 샘플에서 과도한 자원 사용이 발생할 수 있다. 이미지 업로드는 별도 상한, 픽셀 제한, WebP 변환 실패 정책을 가져야 한다.

6.3 Medium

식별자위험도위치판정요약
F-08Mediumconfig/get_upload_config.php미조치설정 조회 엔드포인트가 Access-Control-Allow-Origin: *로 공개됨
F-09Mediumplugin/collab/collab_number_delete.php, plugin/collab/collab_number.php미조치협업 정리 엔드포인트에 CORS 전역 허용과 파일명 불일치가 공존함
F-10Mediumplugin/collab/collab_verification.php, plugin/collab/collab_number.php미조치707/0666 수준의 파일권한 가이드 및 실제 chmod 사용이 보안상 과도함
F-11Mediumjs/core.js, plugin/code/code.js, plugin/table/table.js미조치execCommand, queryCommandState, DOMNodeInserted 등 구식 API 의존도가 높아 호환성 및 안정성 리스크가 존재함
F-12Mediumplugin/ai/*.js, plugin/clipurl/clipurl.js, editor.lib.php미조치외부 서비스 및 외부 폰트 의존성이 기본값으로 포함됨

F-08. 설정 조회 엔드포인트의 전역 CORS

  • config/get_upload_config.php:4-7Access-Control-Allow-Origin: *GET 허용을 직접 설정한다.
  • 제공 정보가 비밀 값은 아니나, 설치 환경별 허용 확장자·용량 정책이 제3자에 노출된다.

'''감사의견'''
중대한 침해 경로는 아니지만, 동일정책 통일 측면에서 불필요한 전역 CORS는 제거하는 편이 타당하다.

F-09. 협업 정리 엔드포인트의 CORS 및 파일명 불일치

  • plugin/collab/collab_number_delete.php:17-19Access-Control-Allow-Origin: *를 허용한다.
  • plugin/collab/collab_number.php:243-250client_ops 파일을 생성한다.
  • 그러나 plugin/collab/collab_number_delete.php:57-65, 101은 삭제 대상에 ops 파일을 사용한다.

'''감사의견'''
host_token 검증이 존재하므로 즉시 삭제 취약점으로 보기는 어렵다. 다만 파일명 불일치로 인한 정리 누락, CORS 확대, 운영 혼선을 유발하므로 개선이 필요하다.

F-10. 협업 기능의 과도한 권한 가이드

  • plugin/collab/collab_verification.php:34, 64/collab 디렉터리에 707 권한 부여를 안내한다.
  • plugin/collab/collab_number.php:59, 71은 생성 파일에 0666 권한을 부여한다.

'''감사의견'''
공유 호스팅이나 다중 사용자 환경에서는 과도한 권한 설정이 부적절하다. 운영 환경에 맞춘 최소 권한 원칙으로 재설계해야 한다.

F-11. 구식 DOM 편집 API 의존

  • js/core.jsDOMNodeInserted, queryCommandState, document.execCommand()에 크게 의존한다.
  • plugin/code/code.js, plugin/table/table.js, plugin/collab/collab.js도 같은 계열 API를 사용한다.

'''감사의견'''
즉시 보안 취약점은 아니지만, 브라우저별 동작 차이와 유지보수 비용이 매우 크다. 9.x 이후 버전에서는 Selection/Range 기반으로 단계적 이행이 필요하다.

F-12. 외부 서비스·외부 폰트 하드 의존

  • editor.lib.php:330-331은 Google Fonts를 직접 호출한다.
  • editor.lib.php:498, readme.txt는 dsclub 링크를 포함한다.
  • plugin/ai/ai.js, plugin/ai_rearrange/ai_rearrange.js, plugin/clipurl/clipurl.js는 외부 API 엔드포인트를 기본값으로 가진다.

'''감사의견'''
기능상 의존성일 뿐 즉시 취약점은 아니다. 다만 사내망·폐쇄망 환경, 개인정보·정책 통제 환경에서는 외부 호출 정책을 분리할 필요가 있다.

6.4 Low

식별자위험도위치판정요약
F-13Lowplugin/file/pdf_view.php부분 양호입력 포맷 검증이 일부 존재하나 구조적 일관성은 부족
F-14Lowreadme.txt, editor.lib.php양호라이선스/버전 표시는 존재하나 런타임 검증 효과는 제한적

7. 문법 검사 및 스팟 테스트

7.1 PHP 문법 검사

아래 PHP 파일 13개에 대해 php -l 검사 결과 문법 오류는 확인되지 않았다.

  • t2_css_min.php
  • config/t2_config.php
  • config/upload_config.php
  • config/get_upload_config.php
  • t2_js_min.php
  • plugin/video/video_view.php
  • plugin/file/pdf_view.php
  • plugin/file/file_upload.php
  • plugin/image/image_upload.php
  • plugin/collab/collab_verification.php
  • plugin/collab/collab_number_delete.php
  • plugin/collab/collab_number.php
  • editor.lib.php

7.2 스팟 테스트 결과

테스트결과의미
T2EDITOR_URL Host 반영 테스트취약 재현악성 HTTP_HOST 값이 URL 상수에 직접 반영됨
validate_upload_file('fake.mp4', 100, 'video')성공 반환내용 검증 없이 확장자·크기만 통과함
정적 스캔: innerHTML =181건공격면이 넓고 수제 sanitization 의존도가 큼
정적 스캔: Access-Control-Allow-Origin: *2건설정 조회와 협업 삭제 엔드포인트에 전역 CORS 존재

8. 보완 우선순위

8.1 즉시 보완 권고(배포 전)

  1. editor.lib.php
  • hidden textarea 및 JS bootstrap 경계의 htmlspecialchars(), json_encode(), safe id 분리 적용
  • </script> 조기 종료 방어 포함
  1. js/core.js
  • 붙여넣기 sanitizer를 검증된 라이브러리로 교체
  • href/src/style 프로토콜·CSS 화이트리스트 적용
  1. plugin/video/video_view.php
  • 외부 URL 직접 허용 제거
  • same-origin 또는 allowlist 도메인만 허용
  • realpath() 기반 경로 포함 검증 추가
  1. config/upload_config.php 및 업로드 엔드포인트
  • MIME/매직바이트/픽셀 수 검증 추가
  • 파일명 정제 및 저장명 난수화 적용
  1. plugin/image/image_upload.php
  • memory_limit, max_execution_time 상한 설정
  • SVG/ICO 처리정책 명확화

8.2 단기 보완 권고(배포 직후)

  1. config/t2_config.php Host 검증 추가
  2. config/get_upload_config.php 전역 CORS 제거
  3. plugin/file/file.js, plugin/video/video.js, plugin/table/table.js의 표시값/URL/클립보드 HTML 이스케이프 적용
  4. plugin/collab/collab_number_delete.php 파일명 체계 client_ops와 일치화
  5. 협업 디렉터리 권한 정책 최소권한 원칙으로 변경

8.3 중기 보완 권고

  1. execCommand, queryCommandState, DOMNodeInserted 의존 제거
  2. 외부 서비스 의존 기능의 on/off 설정 분리
  3. 런타임 minify PHP(t2_css_min.php, t2_js_min.php)를 빌드 타임 산출물로 전환

9. 최종 감사 의견

최종 판정

T2Editor 9.1.1은 기능적 완성도는 높으나, 외부 공개 서비스 기준으로는 그대로 배포하기에 부적절한 항목이 다수 확인되었다. 특히 본문 출력 경계, 붙여넣기 sanitizer, 업로드 검증, 비디오 뷰어, Host 신뢰 경계는 선행 보완이 필요하다. 따라서 본 감사는 '''조건부 부적정''' 의견을 제시한다.

9.1 판단 이유

  • 에디터 핵심 경계에 직접 출력 및 innerHTML 재구성 경로가 다수 존재함
  • 업로드 검증이 확장자/크기 수준에 머물러 우회에 취약함
  • 외부 URL 통제 및 Host 검증이 부재함
  • 협업 보조 엔드포인트에 CORS/권한/정리 불일치가 존재함

9.2 배포 권고

  • '''내부 시험 운영: 가능'''
  • '''폐쇄망·신뢰 사용자 환경: 제한적 가능'''
  • '''외부 공개 서비스: 보안 보완 선행 후 재감사 권고'''

10. 부록

주요 근거 라인
  • config/t2_config.php:25-35
  • config/upload_config.php:138-156
  • config/get_upload_config.php:4-17
  • editor.lib.php:289-295
  • editor.lib.php:494-495
  • editor.lib.php:528-535
  • editor.lib.php:584
  • editor.lib.php:595-597
  • js/core.js:493-517
  • js/core.js:2078-2103
  • plugin/file/file_upload.php:20-24
  • plugin/file/file_upload.php:47-57
  • plugin/image/image_upload.php:8-9
  • plugin/image/image_upload.php:72-76
  • plugin/video/video_view.php:8-19
  • plugin/file/file.js:683-729
  • plugin/video/video.js:269-279
  • plugin/video/video.js:561-565
  • plugin/table/table.js:20-26
  • plugin/collab/collab_number.php:243-250
  • plugin/collab/collab_number_delete.php:17-19
  • plugin/collab/collab_number_delete.php:57-65
r1 최초 작성
2026-04-22 15:20

T2Editor 9.1.1 전수감사 보고서

#감사 #T2Editor

문서 성격

본 문서는 T2Editor 9.1.1 패키지 전체를 대상으로 수행한 전수감사 보고서이다. 감사 범위는 패키지 내 전체 69개 파일이며, 1차 자산 인벤토리 작성, 2차 정적 구조 검토, 3차 위험 패턴 점검, 4차 문법 검사 및 대표 행위 스팟 테스트 순으로 수행하였다.

1. 감사 개요

항목내용
대상 버전T2Editor 9.1.1
기준 자료패키지 원본 /t2editor 디렉터리 전체
조사 방식전수조사·전수감사
조사 대상 수총 69개 파일
파일 구성PHP 13, JS 26, CSS 16, 기타 자산 14
감사 관점서버측 입력검증, 출력안전성, 업로드 경계, 협업 엔드포인트, 클라이언트 런타임, 외부 의존성, 운영 호환성
감사 결과'''외부 공개 서비스 기준 조건부 부적정'''

2. 감사 방법

2.1 조사 절차

  1. 패키지 전체 파일 인벤토리 작성
  2. 기능군별 분류
  • 부트스트랩/설정
  • 코어 에디터 런타임
  • 업로드/뷰어
  • 협업 플러그인
  • 파일/이미지/비디오/표/코드 플러그인
  • 외부 서비스 연계 플러그인
  • 번들·폰트·정적 자산
  1. PHP 파일 문법 검사 수행
  2. 위험 패턴 탐지
  • innerHTML, execCommand, DOMNodeInserted, HTTP_HOST, Access-Control-Allow-Origin: *, move_uploaded_file, flock, chmod, localStorage
  1. 대표 경로 스팟 테스트
  • t2_config.php Host Header 반영 여부
  • upload_config.php 파일 검증 함수 동작 여부

2.2 감사 기준

  • 입력값이 검증 없이 파일시스템, HTML, JS, URL 문맥에 사용되는지 여부
  • 업로드 엔드포인트가 확장자 외의 실질 검증을 수행하는지 여부
  • 뷰어/미리보기 경로가 외부 URL, 상대경로, 임의 속성 삽입에 대해 안전한지 여부
  • 클라이언트 측 sanitizer가 허용 태그·속성·프로토콜을 충분히 제한하는지 여부
  • 보조 엔드포인트가 과도한 CORS, 과도한 권한, 파일명 불일치, 정리 누락을 갖는지 여부
  • 운영 환경 변수(HTTP_HOST, DOCUMENT_ROOT, Origin)를 신뢰해도 되는 방식으로 사용하는지 여부

3. 자산 현황

3.1 기능군별 구성

기능군주요 파일감사 관찰
부트스트랩·설정editor.lib.php, config/t2_config.php, config/upload_config.php, config/get_upload_config.php에디터 HTML/JS 부트스트랩, 경로 계산, 업로드 정책, 설정 노출
코어 런타임js/core.js, js/toolbar.js, js/utils.js편집 동작, 붙여넣기, 히스토리, autosave, sanitizer, 플러그인 로드
업로드·뷰어plugin/file/file_upload.php, plugin/image/image_upload.php, plugin/file/pdf_view.php, plugin/video/video_view.php파일 저장, 이미지 처리, PDF/비디오 표시
협업plugin/collab/*.php, plugin/collab/collab.js룸 생성, 입장/퇴장, 편집 상태 파일 저장, 정리
핵심 플러그인plugin/file, plugin/image, plugin/video, plugin/table, plugin/code파일 블럭, 이미지, 비디오, 테이블, 코드 블럭
외부 서비스 연계plugin/ai, plugin/ai_rearrange, plugin/clipurl, plugin/search, plugin/meme외부 API 및 웹 자산 의존
번들·정적 자산vendor/*, js/pdf*.js, fonts/*배포 번들, 모델 파일, 폰트

3.2 전수조사 대상 파일 목록

파일 목록 보기
  • config/get_upload_config.php
  • config/nsfw_api_browser.js
  • config/t2_config.php
  • config/upload_config.php
  • css/content.css
  • css/core.css
  • css/dark.css
  • editor.lib.php
  • fonts/material-icons/MaterialIcons-Regular.eot
  • fonts/material-icons/MaterialIcons-Regular.ttf
  • fonts/material-icons/MaterialIcons-Regular.woff
  • fonts/material-icons/MaterialIcons-Regular.woff2
  • fonts/material-icons/MaterialIconsOutlined-Regular.woff2
  • fonts/material-icons/font.woff2
  • js/core.js
  • js/jszip.min.js
  • js/pdf.min.js
  • js/pdf.worker.min.js
  • js/toolbar.js
  • js/utils.js
  • plugin/ai/ai.css
  • plugin/ai/ai.js
  • plugin/ai_rearrange/ai_rearrange.css
  • plugin/ai_rearrange/ai_rearrange.js
  • plugin/clipurl/clipurl.css
  • plugin/clipurl/clipurl.js
  • plugin/code/code.css
  • plugin/code/code.js
  • plugin/collab/collab.css
  • plugin/collab/collab.js
  • plugin/collab/collab_number.php
  • plugin/collab/collab_number_delete.php
  • plugin/collab/collab_verification.php
  • plugin/draw/draw.css
  • plugin/draw/draw.js
  • plugin/export/export.js
  • plugin/export/export_html_skin.html
  • plugin/file/file.css
  • plugin/file/file.js
  • plugin/file/file_upload.php
  • plugin/file/pdf_view.php
  • plugin/image/image.css
  • plugin/image/image.js
  • plugin/image/image_upload.php
  • plugin/link/link.css
  • plugin/link/link.js
  • plugin/meme/meme.css
  • plugin/meme/meme.js
  • plugin/search/search.css
  • plugin/search/search.js
  • plugin/table/table.css
  • plugin/table/table.js
  • plugin/video/video.css
  • plugin/video/video.js
  • plugin/video/video_view.php
  • readme.txt
  • t2_css_min.php
  • t2_js_min.php
  • vendor/nsfwjs/models/mobilenet_v2_mid/group1-shard1of2
  • vendor/nsfwjs/models/mobilenet_v2_mid/group1-shard2of2
  • vendor/nsfwjs/models/mobilenet_v2_mid/model.json
  • vendor/nsfwjs/nsfwjs.min.js
  • vendor/tfjs-backend-wasm/tf-backend-wasm.min.js
  • vendor/tfjs-backend-wasm/tfjs-backend-wasm-simd.wasm
  • vendor/tfjs-backend-wasm/tfjs-backend-wasm-threaded-simd.wasm
  • vendor/tfjs-backend-wasm/tfjs-backend-wasm.wasm
  • vendor/tfjs-backend-webgl/tf-backend-webgl.min.js
  • vendor/tfjs-backend-webgpu/tf-backend-webgpu.min.js
  • vendor/tfjs/tf.min.js

4. 총괄 판단

총평

T2Editor 9.1.1은 편집기 기능 범위가 넓고 플러그인 구조도 비교적 정돈되어 있다. 다만 보안 관점에서 보면 서버측 검증 경계가 얕고, 클라이언트 측 HTML 재구성 경로가 공격면을 크게 노출하며, 업로드·비디오·협업 보조 엔드포인트에 다수의 구조적 취약점이 존재한다. 특히 editor.lib.php, js/core.js, plugin/video/video_view.php, plugin/file/file_upload.php, plugin/image/image_upload.php는 우선 보완 대상이다.

4.1 종합 판정

구분판정의견
기능 완성도양호플러그인 수와 사용성은 충분함
서버측 입력검증미흡확장자·크기 중심 검증, URL·Host·Origin 통제 부족
출력 안전성미흡raw textarea, JS 문자열, innerHTML 재구성 경로 다수
업로드 경계미흡MIME/매직바이트 검증 부재, 이미지 자원 제한 부재
협업 보조 엔드포인트주의파일권한·CORS·정리 로직 불일치 존재
운영 호환성보통경로 자동 계산은 있으나 Host 신뢰가 과도함
외부 공개 서비스 적합성'''조건부 부적정'''보안 선행 보완 없이는 공개 운영 비권고

5. 주요 강점

  • 전체 PHP 파일 13개에 대해 문법 오류가 확인되지 않았다.
  • 이미지 업로드 경로에서 getimagesize() 기반 실제 이미지 여부 확인은 수행한다.
  • 협업 기능은 flock() 기반 잠금과 원자적 JSON 업데이트 구조를 일부 도입하고 있다.
  • PDF 뷰어와 코드 블럭, 테이블, 파일 블럭 등 기능 모듈화는 비교적 명확하다.
  • 라이선스/버전 정보와 기본 플러그인 우선순위 관리 구조는 일관적이다.

6. 세부 감사 결과

6.1 Critical

식별자위험도위치판정요약
F-01Criticaleditor.lib.php미조치본문 내용과 ID 값이 HTML/JS 문맥에 직접 삽입되어 구조 파손 및 XSS 가능성이 존재함
F-02Criticaljs/core.js미조치붙여넣기 및 sanitizer가 innerHTML과 얕은 allowlist에 의존하여 DOM XSS 우회 가능성이 큼

F-01. 본문 로딩/저장 경계의 직접 출력

  • editor.lib.php:289-295에서 본문을 JS 문자열로 가공하나 </script> 조기 종료와 컨텍스트 분리가 충분하지 않다.
  • editor.lib.php:494-495에서 hidden textarea에 $id, $content를 그대로 출력한다.
  • editor.lib.php:528-535에서 window.<id>_editortempDiv.innerHTML = contentToLoad를 직접 수행한다.
  • editor.lib.php:584에서도 일반 textarea 경로에 본문을 그대로 출력한다.
  • editor.lib.php:595-597에서 저장 직전 다시 innerHTML 재구성을 수행한다.

'''감사의견'''
본문 또는 필드 ID가 신뢰되지 않는 경로에서 유입될 경우 DOM 파손, 스크립트 블록 조기 종료, HTML 속성 탈출, 저장 시 이차적 구조 오염으로 이어질 수 있다. 본 항목은 패키지의 핵심 출력 경계에 해당하므로 우선순위가 가장 높다.

F-02. 코어 sanitizer 및 붙여넣기 경계의 구조적 취약

  • js/core.js:493-517에서 붙여넣기 내용을 tempDiv.innerHTML로 해석한 후 currentBlock.innerHTML = beforeText + sanitizedHTML + afterText 방식으로 다시 삽입한다.
  • js/core.js:2078-2103sanitizeHTML()href, src, style을 허용하면서 프로토콜 및 스타일 값 검증을 하지 않는다.
  • allowedTags에는 a, img, span, div 등이 포함되어 있어 속성 조합 우회 가능성이 존재한다.

'''감사의견'''
전형적인 “수제 sanitizer” 구조이며, 프로토콜·CSS·이벤트 간접 주입을 방어하기에 부족하다. 특히 붙여넣기 경계는 외부 HTML이 대량 유입되는 지점이므로, 실제 서비스 환경에서는 DOMPurify급 검증기로 교체하는 편이 타당하다.

6.2 High

식별자위험도위치판정요약
F-03Highplugin/video/video_view.php미조치외부 URL 및 상대경로를 충분히 제한하지 않아 비디오 뷰어가 비허용 URL을 그대로 렌더링할 수 있음
F-04Highconfig/upload_config.php, plugin/file/file_upload.php, plugin/image/image_upload.php미조치업로드 검증이 실질적으로 확장자·크기 중심이며 MIME/매직바이트 검증이 없음
F-05Highplugin/file/file.js, plugin/video/video.js, plugin/table/table.js미조치파일명/URL/클립보드 HTML이 innerHTML로 재삽입되어 XSS 공격면이 존재함
F-06Highconfig/t2_config.php미조치HTTP_HOST를 검증 없이 신뢰하여 URL 계산에 사용함
F-07Highplugin/image/image_upload.php미조치무제한 메모리/실행시간 설정으로 자원 고갈 위험이 큼

F-03. 비디오 뷰어의 외부 URL 통과 및 경로 검증 부재

  • plugin/video/video_view.php:8-19에서 $_GET['video']를 받아 http로 시작하지 않으면 절대경로로 변환한다.
  • 즉, http://, https:// 형태의 외부 URL은 그대로 통과한다.
  • plugin/video/video_view.php:24-26은 확장자만 확인하고, 실제 허용 도메인 또는 데이터 디렉터리 하위 여부를 검증하지 않는다.

'''감사의견'''
브라우저 기준의 외부 요청 유발, 핫링킹, 예기치 않은 제3자 호스트 렌더링, 상대경로 오염 가능성이 있다. 비디오 뷰어는 same-origin 또는 명시적 allowlist 기반으로 제한해야 한다.

F-04. 업로드 경계의 실질 검증 부재

  • config/upload_config.php:138-156validate_upload_file()는 확장자와 파일 크기만 검사한다.
  • plugin/file/file_upload.php:47-50은 해당 함수를 그대로 사용한다.
  • plugin/image/image_upload.php:72-76 역시 같은 함수를 호출하나, 본질적으로 확장자·크기 확인에 머문다.
  • 스팟 테스트 결과 validate_upload_file('fake.mp4', 100, 'video')는 성공을 반환하였다.

'''감사의견'''
현재 구조는 위장 확장자, 내용 불일치 파일, 악성 샘플에 취약하다. 최소한 MIME, 매직바이트, 이미지 픽셀 한도, 업로드 실패 원인 세분화가 필요하다.

F-05. 플러그인별 HTML 재삽입 경계

  • plugin/file/file.js:683-729fileInfo.url, fileInfo.original_name을 오디오/일반 파일 블럭 innerHTML에 직접 삽입한다.
  • plugin/video/video.js:269-279은 업로드 후 미리보기에서 data.file.url, file.name을 그대로 사용한다.
  • plugin/video/video.js:561-565는 URL 수정 모달의 value="${currentUrl}"에 현재 URL을 그대로 넣는다.
  • plugin/table/table.js:20-26은 클립보드 HTML에서 tablecloneNode(true)로 복사하나, 이벤트 속성 제거가 없다.

'''감사의견'''
서버 응답, 파일명, 클립보드 HTML을 신뢰하는 구조다. 업로드 응답이 오염되거나 사용자가 악성 파일명·테이블 HTML을 다루는 환경에서는 DOM XSS가 가능하다.

F-06. Host Header 신뢰

  • config/t2_config.php:25-35에서 $_SERVER['HTTP_HOST']를 그대로 T2EDITOR_URL 계산에 사용한다.
  • 스팟 테스트 결과 악성 Host 문자열이 URL 상수에 그대로 반영되었다.

'''감사의견'''
역프록시 설정이 약하거나 Host 헤더 검증이 없는 배포 환경에서는 링크·리소스 경로 위변조가 가능하다. Host는 allowlist 또는 정규식 검증 후 사용해야 한다.

F-07. 이미지 처리 자원 한도 부재

  • plugin/image/image_upload.php:8-9에서 memory_limit = -1, max_execution_time = 0을 설정한다.
  • 이미지 크기·픽셀 수·예상 메모리 사용량을 제한하지 않는다.

'''감사의견'''
고해상도 이미지, 손상된 이미지, 압축폭탄 계열 샘플에서 과도한 자원 사용이 발생할 수 있다. 이미지 업로드는 별도 상한, 픽셀 제한, WebP 변환 실패 정책을 가져야 한다.

6.3 Medium

식별자위험도위치판정요약
F-08Mediumconfig/get_upload_config.php미조치설정 조회 엔드포인트가 Access-Control-Allow-Origin: *로 공개됨
F-09Mediumplugin/collab/collab_number_delete.php, plugin/collab/collab_number.php미조치협업 정리 엔드포인트에 CORS 전역 허용과 파일명 불일치가 공존함
F-10Mediumplugin/collab/collab_verification.php, plugin/collab/collab_number.php미조치707/0666 수준의 파일권한 가이드 및 실제 chmod 사용이 보안상 과도함
F-11Mediumjs/core.js, plugin/code/code.js, plugin/table/table.js미조치execCommand, queryCommandState, DOMNodeInserted 등 구식 API 의존도가 높아 호환성 및 안정성 리스크가 존재함
F-12Mediumplugin/ai/*.js, plugin/clipurl/clipurl.js, editor.lib.php미조치외부 서비스 및 외부 폰트 의존성이 기본값으로 포함됨

F-08. 설정 조회 엔드포인트의 전역 CORS

  • config/get_upload_config.php:4-7Access-Control-Allow-Origin: *GET 허용을 직접 설정한다.
  • 제공 정보가 비밀 값은 아니나, 설치 환경별 허용 확장자·용량 정책이 제3자에 노출된다.

'''감사의견'''
중대한 침해 경로는 아니지만, 동일정책 통일 측면에서 불필요한 전역 CORS는 제거하는 편이 타당하다.

F-09. 협업 정리 엔드포인트의 CORS 및 파일명 불일치

  • plugin/collab/collab_number_delete.php:17-19Access-Control-Allow-Origin: *를 허용한다.
  • plugin/collab/collab_number.php:243-250client_ops 파일을 생성한다.
  • 그러나 plugin/collab/collab_number_delete.php:57-65, 101은 삭제 대상에 ops 파일을 사용한다.

'''감사의견'''
host_token 검증이 존재하므로 즉시 삭제 취약점으로 보기는 어렵다. 다만 파일명 불일치로 인한 정리 누락, CORS 확대, 운영 혼선을 유발하므로 개선이 필요하다.

F-10. 협업 기능의 과도한 권한 가이드

  • plugin/collab/collab_verification.php:34, 64/collab 디렉터리에 707 권한 부여를 안내한다.
  • plugin/collab/collab_number.php:59, 71은 생성 파일에 0666 권한을 부여한다.

'''감사의견'''
공유 호스팅이나 다중 사용자 환경에서는 과도한 권한 설정이 부적절하다. 운영 환경에 맞춘 최소 권한 원칙으로 재설계해야 한다.

F-11. 구식 DOM 편집 API 의존

  • js/core.jsDOMNodeInserted, queryCommandState, document.execCommand()에 크게 의존한다.
  • plugin/code/code.js, plugin/table/table.js, plugin/collab/collab.js도 같은 계열 API를 사용한다.

'''감사의견'''
즉시 보안 취약점은 아니지만, 브라우저별 동작 차이와 유지보수 비용이 매우 크다. 9.x 이후 버전에서는 Selection/Range 기반으로 단계적 이행이 필요하다.

F-12. 외부 서비스·외부 폰트 하드 의존

  • editor.lib.php:330-331은 Google Fonts를 직접 호출한다.
  • editor.lib.php:498, readme.txt는 dsclub 링크를 포함한다.
  • plugin/ai/ai.js, plugin/ai_rearrange/ai_rearrange.js, plugin/clipurl/clipurl.js는 외부 API 엔드포인트를 기본값으로 가진다.

'''감사의견'''
기능상 의존성일 뿐 즉시 취약점은 아니다. 다만 사내망·폐쇄망 환경, 개인정보·정책 통제 환경에서는 외부 호출 정책을 분리할 필요가 있다.

6.4 Low

식별자위험도위치판정요약
F-13Lowplugin/file/pdf_view.php부분 양호입력 포맷 검증이 일부 존재하나 구조적 일관성은 부족
F-14Lowreadme.txt, editor.lib.php양호라이선스/버전 표시는 존재하나 런타임 검증 효과는 제한적

7. 문법 검사 및 스팟 테스트

7.1 PHP 문법 검사

아래 PHP 파일 13개에 대해 php -l 검사 결과 문법 오류는 확인되지 않았다.

  • t2_css_min.php
  • config/t2_config.php
  • config/upload_config.php
  • config/get_upload_config.php
  • t2_js_min.php
  • plugin/video/video_view.php
  • plugin/file/pdf_view.php
  • plugin/file/file_upload.php
  • plugin/image/image_upload.php
  • plugin/collab/collab_verification.php
  • plugin/collab/collab_number_delete.php
  • plugin/collab/collab_number.php
  • editor.lib.php

7.2 스팟 테스트 결과

테스트결과의미
T2EDITOR_URL Host 반영 테스트취약 재현악성 HTTP_HOST 값이 URL 상수에 직접 반영됨
validate_upload_file('fake.mp4', 100, 'video')성공 반환내용 검증 없이 확장자·크기만 통과함
정적 스캔: innerHTML =181건공격면이 넓고 수제 sanitization 의존도가 큼
정적 스캔: Access-Control-Allow-Origin: *2건설정 조회와 협업 삭제 엔드포인트에 전역 CORS 존재

8. 보완 우선순위

8.1 즉시 보완 권고(배포 전)

  1. editor.lib.php
  • hidden textarea 및 JS bootstrap 경계의 htmlspecialchars(), json_encode(), safe id 분리 적용
  • </script> 조기 종료 방어 포함
  1. js/core.js
  • 붙여넣기 sanitizer를 검증된 라이브러리로 교체
  • href/src/style 프로토콜·CSS 화이트리스트 적용
  1. plugin/video/video_view.php
  • 외부 URL 직접 허용 제거
  • same-origin 또는 allowlist 도메인만 허용
  • realpath() 기반 경로 포함 검증 추가
  1. config/upload_config.php 및 업로드 엔드포인트
  • MIME/매직바이트/픽셀 수 검증 추가
  • 파일명 정제 및 저장명 난수화 적용
  1. plugin/image/image_upload.php
  • memory_limit, max_execution_time 상한 설정
  • SVG/ICO 처리정책 명확화

8.2 단기 보완 권고(배포 직후)

  1. config/t2_config.php Host 검증 추가
  2. config/get_upload_config.php 전역 CORS 제거
  3. plugin/file/file.js, plugin/video/video.js, plugin/table/table.js의 표시값/URL/클립보드 HTML 이스케이프 적용
  4. plugin/collab/collab_number_delete.php 파일명 체계 client_ops와 일치화
  5. 협업 디렉터리 권한 정책 최소권한 원칙으로 변경

8.3 중기 보완 권고

  1. execCommand, queryCommandState, DOMNodeInserted 의존 제거
  2. 외부 서비스 의존 기능의 on/off 설정 분리
  3. 런타임 minify PHP(t2_css_min.php, t2_js_min.php)를 빌드 타임 산출물로 전환

9. 최종 감사 의견

최종 판정

T2Editor 9.1.1은 기능적 완성도는 높으나, 외부 공개 서비스 기준으로는 그대로 배포하기에 부적절한 항목이 다수 확인되었다. 특히 본문 출력 경계, 붙여넣기 sanitizer, 업로드 검증, 비디오 뷰어, Host 신뢰 경계는 선행 보완이 필요하다. 따라서 본 감사는 '''조건부 부적정''' 의견을 제시한다.

9.1 판단 이유

  • 에디터 핵심 경계에 직접 출력 및 innerHTML 재구성 경로가 다수 존재함
  • 업로드 검증이 확장자/크기 수준에 머물러 우회에 취약함
  • 외부 URL 통제 및 Host 검증이 부재함
  • 협업 보조 엔드포인트에 CORS/권한/정리 불일치가 존재함

9.2 배포 권고

  • '''내부 시험 운영: 가능'''
  • '''폐쇄망·신뢰 사용자 환경: 제한적 가능'''
  • '''외부 공개 서비스: 보안 보완 선행 후 재감사 권고'''

10. 부록

주요 근거 라인
  • config/t2_config.php:25-35
  • config/upload_config.php:138-156
  • config/get_upload_config.php:4-17
  • editor.lib.php:289-295
  • editor.lib.php:494-495
  • editor.lib.php:528-535
  • editor.lib.php:584
  • editor.lib.php:595-597
  • js/core.js:493-517
  • js/core.js:2078-2103
  • plugin/file/file_upload.php:20-24
  • plugin/file/file_upload.php:47-57
  • plugin/image/image_upload.php:8-9
  • plugin/image/image_upload.php:72-76
  • plugin/video/video_view.php:8-19
  • plugin/file/file.js:683-729
  • plugin/video/video.js:269-279
  • plugin/video/video.js:561-565
  • plugin/table/table.js:20-26
  • plugin/collab/collab_number.php:243-250
  • plugin/collab/collab_number_delete.php:17-19
  • plugin/collab/collab_number_delete.php:57-65
라인 단위 비교
이전 새 버전
1 = T2Editor 9.1.1 전수감사 보고서 = 1 = T2Editor 9.1.1 전수감사 보고서 =
2   2  
3 [목차] 3 [목차]
4   4  
5 [[분류:감사]] 5 [[분류:감사]]
6 [[분류:T2Editor]] 6 [[분류:T2Editor]]
7   7  
8 [note(문서 성격)] 8 [note(문서 성격)]
9 본 문서는 T2Editor 9.1.1 패키지 전체를 대상으로 수행한 전수감사 보고서이다. 감사 범위는 패키지 내 전체 69개 파일이며, 1차 자산 인벤토리 작성, 2차 정적 구조 검토, 3차 위험 패턴 점검, 4차 문법 검사 및 대표 행위 스팟 테스트 순으로 수행하였다. 9 본 문서는 T2Editor 9.1.1 패키지 전체를 대상으로 수행한 전수감사 보고서이다. 감사 범위는 패키지 내 전체 69개 파일이며, 1차 자산 인벤토리 작성, 2차 정적 구조 검토, 3차 위험 패턴 점검, 4차 문법 검사 및 대표 행위 스팟 테스트 순으로 수행하였다.
10 [/note] 10 [/note]
11   11  
12 == 1. 감사 개요 == 12 == 1. 감사 개요 ==
13   13  
14 ||= 항목 ||= 내용 || 14 ||= 항목 ||= 내용 ||
15 || 대상 버전 || T2Editor 9.1.1 || 15 || 대상 버전 || T2Editor 9.1.1 ||
16 || 기준 자료 || 패키지 원본 `/t2editor` 디렉터리 전체 || 16 || 기준 자료 || 패키지 원본 `/t2editor` 디렉터리 전체 ||
17 || 조사 방식 || 전수조사·전수감사 || 17 || 조사 방식 || 전수조사·전수감사 ||
18 || 조사 대상 수 || 총 69개 파일 || 18 || 조사 대상 수 || 총 69개 파일 ||
19 || 파일 구성 || PHP 13, JS 26, CSS 16, 기타 자산 14 || 19 || 파일 구성 || PHP 13, JS 26, CSS 16, 기타 자산 14 ||
20 || 감사 관점 || 서버측 입력검증, 출력안전성, 업로드 경계, 협업 엔드포인트, 클라이언트 런타임, 외부 의존성, 운영 호환성 || 20 || 감사 관점 || 서버측 입력검증, 출력안전성, 업로드 경계, 협업 엔드포인트, 클라이언트 런타임, 외부 의존성, 운영 호환성 ||
21 || 감사 결과 || '''외부 공개 서비스 기준 조건부 부적정''' || 21 || 감사 결과 || '''외부 공개 서비스 기준 조건부 부적정''' ||
22   22  
23 == 2. 감사 방법 == 23 == 2. 감사 방법 ==
24   24  
25 ### 2.1 조사 절차 25 ### 2.1 조사 절차
26 1. 패키지 전체 파일 인벤토리 작성 26 1. 패키지 전체 파일 인벤토리 작성
27 2. 기능군별 분류 27 2. 기능군별 분류
28 - 부트스트랩/설정 28 - 부트스트랩/설정
29 - 코어 에디터 런타임 29 - 코어 에디터 런타임
30 - 업로드/뷰어 30 - 업로드/뷰어
31 - 협업 플러그인 31 - 협업 플러그인
32 - 파일/이미지/비디오/표/코드 플러그인 32 - 파일/이미지/비디오/표/코드 플러그인
33 - 외부 서비스 연계 플러그인 33 - 외부 서비스 연계 플러그인
34 - 번들·폰트·정적 자산 34 - 번들·폰트·정적 자산
35 3. PHP 파일 문법 검사 수행 35 3. PHP 파일 문법 검사 수행
36 4. 위험 패턴 탐지 36 4. 위험 패턴 탐지
37 - `innerHTML`, `execCommand`, `DOMNodeInserted`, `HTTP_HOST`, `Access-Control-Allow-Origin: *`, `move_uploaded_file`, `flock`, `chmod`, `localStorage` 37 - `innerHTML`, `execCommand`, `DOMNodeInserted`, `HTTP_HOST`, `Access-Control-Allow-Origin: *`, `move_uploaded_file`, `flock`, `chmod`, `localStorage`
38 5. 대표 경로 스팟 테스트 38 5. 대표 경로 스팟 테스트
39 - `t2_config.php` Host Header 반영 여부 39 - `t2_config.php` Host Header 반영 여부
40 - `upload_config.php` 파일 검증 함수 동작 여부 40 - `upload_config.php` 파일 검증 함수 동작 여부
41   41  
42 ### 2.2 감사 기준 42 ### 2.2 감사 기준
43 - 입력값이 검증 없이 파일시스템, HTML, JS, URL 문맥에 사용되는지 여부 43 - 입력값이 검증 없이 파일시스템, HTML, JS, URL 문맥에 사용되는지 여부
44 - 업로드 엔드포인트가 확장자 외의 실질 검증을 수행하는지 여부 44 - 업로드 엔드포인트가 확장자 외의 실질 검증을 수행하는지 여부
45 - 뷰어/미리보기 경로가 외부 URL, 상대경로, 임의 속성 삽입에 대해 안전한지 여부 45 - 뷰어/미리보기 경로가 외부 URL, 상대경로, 임의 속성 삽입에 대해 안전한지 여부
46 - 클라이언트 측 sanitizer가 허용 태그·속성·프로토콜을 충분히 제한하는지 여부 46 - 클라이언트 측 sanitizer가 허용 태그·속성·프로토콜을 충분히 제한하는지 여부
47 - 보조 엔드포인트가 과도한 CORS, 과도한 권한, 파일명 불일치, 정리 누락을 갖는지 여부 47 - 보조 엔드포인트가 과도한 CORS, 과도한 권한, 파일명 불일치, 정리 누락을 갖는지 여부
48 - 운영 환경 변수(`HTTP_HOST`, `DOCUMENT_ROOT`, `Origin`)를 신뢰해도 되는 방식으로 사용하는지 여부 48 - 운영 환경 변수(`HTTP_HOST`, `DOCUMENT_ROOT`, `Origin`)를 신뢰해도 되는 방식으로 사용하는지 여부
49   49  
50 == 3. 자산 현황 == 50 == 3. 자산 현황 ==
51   51  
52 ### 3.1 기능군별 구성 52 ### 3.1 기능군별 구성
53 ||= 기능군 ||= 주요 파일 || 감사 관찰 || 53 ||= 기능군 ||= 주요 파일 || 감사 관찰 ||
54 || 부트스트랩·설정 || `editor.lib.php`, `config/t2_config.php`, `config/upload_config.php`, `config/get_upload_config.php` || 에디터 HTML/JS 부트스트랩, 경로 계산, 업로드 정책, 설정 노출 || 54 || 부트스트랩·설정 || `editor.lib.php`, `config/t2_config.php`, `config/upload_config.php`, `config/get_upload_config.php` || 에디터 HTML/JS 부트스트랩, 경로 계산, 업로드 정책, 설정 노출 ||
55 || 코어 런타임 || `js/core.js`, `js/toolbar.js`, `js/utils.js` || 편집 동작, 붙여넣기, 히스토리, autosave, sanitizer, 플러그인 로드 || 55 || 코어 런타임 || `js/core.js`, `js/toolbar.js`, `js/utils.js` || 편집 동작, 붙여넣기, 히스토리, autosave, sanitizer, 플러그인 로드 ||
56 || 업로드·뷰어 || `plugin/file/file_upload.php`, `plugin/image/image_upload.php`, `plugin/file/pdf_view.php`, `plugin/video/video_view.php` || 파일 저장, 이미지 처리, PDF/비디오 표시 || 56 || 업로드·뷰어 || `plugin/file/file_upload.php`, `plugin/image/image_upload.php`, `plugin/file/pdf_view.php`, `plugin/video/video_view.php` || 파일 저장, 이미지 처리, PDF/비디오 표시 ||
57 || 협업 || `plugin/collab/*.php`, `plugin/collab/collab.js` || 룸 생성, 입장/퇴장, 편집 상태 파일 저장, 정리 || 57 || 협업 || `plugin/collab/*.php`, `plugin/collab/collab.js` || 룸 생성, 입장/퇴장, 편집 상태 파일 저장, 정리 ||
58 || 핵심 플러그인 || `plugin/file`, `plugin/image`, `plugin/video`, `plugin/table`, `plugin/code` || 파일 블럭, 이미지, 비디오, 테이블, 코드 블럭 || 58 || 핵심 플러그인 || `plugin/file`, `plugin/image`, `plugin/video`, `plugin/table`, `plugin/code` || 파일 블럭, 이미지, 비디오, 테이블, 코드 블럭 ||
59 || 외부 서비스 연계 || `plugin/ai`, `plugin/ai_rearrange`, `plugin/clipurl`, `plugin/search`, `plugin/meme` || 외부 API 및 웹 자산 의존 || 59 || 외부 서비스 연계 || `plugin/ai`, `plugin/ai_rearrange`, `plugin/clipurl`, `plugin/search`, `plugin/meme` || 외부 API 및 웹 자산 의존 ||
60 || 번들·정적 자산 || `vendor/*`, `js/pdf*.js`, `fonts/*` || 배포 번들, 모델 파일, 폰트 || 60 || 번들·정적 자산 || `vendor/*`, `js/pdf*.js`, `fonts/*` || 배포 번들, 모델 파일, 폰트 ||
61   61  
62 ### 3.2 전수조사 대상 파일 목록 62 ### 3.2 전수조사 대상 파일 목록
63 [folding(파일 목록 보기)] 63 [folding(파일 목록 보기)]
64 - `config/get_upload_config.php` 64 - `config/get_upload_config.php`
65 - `config/nsfw_api_browser.js` 65 - `config/nsfw_api_browser.js`
66 - `config/t2_config.php` 66 - `config/t2_config.php`
67 - `config/upload_config.php` 67 - `config/upload_config.php`
68 - `css/content.css` 68 - `css/content.css`
69 - `css/core.css` 69 - `css/core.css`
70 - `css/dark.css` 70 - `css/dark.css`
71 - `editor.lib.php` 71 - `editor.lib.php`
72 - `fonts/material-icons/MaterialIcons-Regular.eot` 72 - `fonts/material-icons/MaterialIcons-Regular.eot`
73 - `fonts/material-icons/MaterialIcons-Regular.ttf` 73 - `fonts/material-icons/MaterialIcons-Regular.ttf`
74 - `fonts/material-icons/MaterialIcons-Regular.woff` 74 - `fonts/material-icons/MaterialIcons-Regular.woff`
75 - `fonts/material-icons/MaterialIcons-Regular.woff2` 75 - `fonts/material-icons/MaterialIcons-Regular.woff2`
76 - `fonts/material-icons/MaterialIconsOutlined-Regular.woff2` 76 - `fonts/material-icons/MaterialIconsOutlined-Regular.woff2`
77 - `fonts/material-icons/font.woff2` 77 - `fonts/material-icons/font.woff2`
78 - `js/core.js` 78 - `js/core.js`
79 - `js/jszip.min.js` 79 - `js/jszip.min.js`
80 - `js/pdf.min.js` 80 - `js/pdf.min.js`
81 - `js/pdf.worker.min.js` 81 - `js/pdf.worker.min.js`
82 - `js/toolbar.js` 82 - `js/toolbar.js`
83 - `js/utils.js` 83 - `js/utils.js`
84 - `plugin/ai/ai.css` 84 - `plugin/ai/ai.css`
85 - `plugin/ai/ai.js` 85 - `plugin/ai/ai.js`
86 - `plugin/ai_rearrange/ai_rearrange.css` 86 - `plugin/ai_rearrange/ai_rearrange.css`
87 - `plugin/ai_rearrange/ai_rearrange.js` 87 - `plugin/ai_rearrange/ai_rearrange.js`
88 - `plugin/clipurl/clipurl.css` 88 - `plugin/clipurl/clipurl.css`
89 - `plugin/clipurl/clipurl.js` 89 - `plugin/clipurl/clipurl.js`
90 - `plugin/code/code.css` 90 - `plugin/code/code.css`
91 - `plugin/code/code.js` 91 - `plugin/code/code.js`
92 - `plugin/collab/collab.css` 92 - `plugin/collab/collab.css`
93 - `plugin/collab/collab.js` 93 - `plugin/collab/collab.js`
94 - `plugin/collab/collab_number.php` 94 - `plugin/collab/collab_number.php`
95 - `plugin/collab/collab_number_delete.php` 95 - `plugin/collab/collab_number_delete.php`
96 - `plugin/collab/collab_verification.php` 96 - `plugin/collab/collab_verification.php`
97 - `plugin/draw/draw.css` 97 - `plugin/draw/draw.css`
98 - `plugin/draw/draw.js` 98 - `plugin/draw/draw.js`
99 - `plugin/export/export.js` 99 - `plugin/export/export.js`
100 - `plugin/export/export_html_skin.html` 100 - `plugin/export/export_html_skin.html`
101 - `plugin/file/file.css` 101 - `plugin/file/file.css`
102 - `plugin/file/file.js` 102 - `plugin/file/file.js`
103 - `plugin/file/file_upload.php` 103 - `plugin/file/file_upload.php`
104 - `plugin/file/pdf_view.php` 104 - `plugin/file/pdf_view.php`
105 - `plugin/image/image.css` 105 - `plugin/image/image.css`
106 - `plugin/image/image.js` 106 - `plugin/image/image.js`
107 - `plugin/image/image_upload.php` 107 - `plugin/image/image_upload.php`
108 - `plugin/link/link.css` 108 - `plugin/link/link.css`
109 - `plugin/link/link.js` 109 - `plugin/link/link.js`
110 - `plugin/meme/meme.css` 110 - `plugin/meme/meme.css`
111 - `plugin/meme/meme.js` 111 - `plugin/meme/meme.js`
112 - `plugin/search/search.css` 112 - `plugin/search/search.css`
113 - `plugin/search/search.js` 113 - `plugin/search/search.js`
114 - `plugin/table/table.css` 114 - `plugin/table/table.css`
115 - `plugin/table/table.js` 115 - `plugin/table/table.js`
116 - `plugin/video/video.css` 116 - `plugin/video/video.css`
117 - `plugin/video/video.js` 117 - `plugin/video/video.js`
118 - `plugin/video/video_view.php` 118 - `plugin/video/video_view.php`
119 - `readme.txt` 119 - `readme.txt`
120 - `t2_css_min.php` 120 - `t2_css_min.php`
121 - `t2_js_min.php` 121 - `t2_js_min.php`
122 - `vendor/nsfwjs/models/mobilenet_v2_mid/group1-shard1of2` 122 - `vendor/nsfwjs/models/mobilenet_v2_mid/group1-shard1of2`
123 - `vendor/nsfwjs/models/mobilenet_v2_mid/group1-shard2of2` 123 - `vendor/nsfwjs/models/mobilenet_v2_mid/group1-shard2of2`
124 - `vendor/nsfwjs/models/mobilenet_v2_mid/model.json` 124 - `vendor/nsfwjs/models/mobilenet_v2_mid/model.json`
125 - `vendor/nsfwjs/nsfwjs.min.js` 125 - `vendor/nsfwjs/nsfwjs.min.js`
126 - `vendor/tfjs-backend-wasm/tf-backend-wasm.min.js` 126 - `vendor/tfjs-backend-wasm/tf-backend-wasm.min.js`
127 - `vendor/tfjs-backend-wasm/tfjs-backend-wasm-simd.wasm` 127 - `vendor/tfjs-backend-wasm/tfjs-backend-wasm-simd.wasm`
128 - `vendor/tfjs-backend-wasm/tfjs-backend-wasm-threaded-simd.wasm` 128 - `vendor/tfjs-backend-wasm/tfjs-backend-wasm-threaded-simd.wasm`
129 - `vendor/tfjs-backend-wasm/tfjs-backend-wasm.wasm` 129 - `vendor/tfjs-backend-wasm/tfjs-backend-wasm.wasm`
130 - `vendor/tfjs-backend-webgl/tf-backend-webgl.min.js` 130 - `vendor/tfjs-backend-webgl/tf-backend-webgl.min.js`
131 - `vendor/tfjs-backend-webgpu/tf-backend-webgpu.min.js` 131 - `vendor/tfjs-backend-webgpu/tf-backend-webgpu.min.js`
132 - `vendor/tfjs/tf.min.js` 132 - `vendor/tfjs/tf.min.js`
133 [/folding] 133 [/folding]
134   134  
135 == 4. 총괄 판단 == 135 == 4. 총괄 판단 ==
136   136  
137 [note(총평)] 137 [note(총평)]
138 T2Editor 9.1.1은 편집기 기능 범위가 넓고 플러그인 구조도 비교적 정돈되어 있다. 다만 보안 관점에서 보면 서버측 검증 경계가 얕고, 클라이언트 측 HTML 재구성 경로가 공격면을 크게 노출하며, 업로드·비디오·협업 보조 엔드포인트에 다수의 구조적 취약점이 존재한다. 특히 `editor.lib.php`, `js/core.js`, `plugin/video/video_view.php`, `plugin/file/file_upload.php`, `plugin/image/image_upload.php`는 우선 보완 대상이다. 138 T2Editor 9.1.1은 편집기 기능 범위가 넓고 플러그인 구조도 비교적 정돈되어 있다. 다만 보안 관점에서 보면 서버측 검증 경계가 얕고, 클라이언트 측 HTML 재구성 경로가 공격면을 크게 노출하며, 업로드·비디오·협업 보조 엔드포인트에 다수의 구조적 취약점이 존재한다. 특히 `editor.lib.php`, `js/core.js`, `plugin/video/video_view.php`, `plugin/file/file_upload.php`, `plugin/image/image_upload.php`는 우선 보완 대상이다.
139 [/note] 139 [/note]
140   140  
141 ### 4.1 종합 판정 141 ### 4.1 종합 판정
142 ||= 구분 ||= 판정 ||= 의견 || 142 ||= 구분 ||= 판정 ||= 의견 ||
143 || 기능 완성도 || 양호 || 플러그인 수와 사용성은 충분함 || 143 || 기능 완성도 || 양호 || 플러그인 수와 사용성은 충분함 ||
144 || 서버측 입력검증 || 미흡 || 확장자·크기 중심 검증, URL·Host·Origin 통제 부족 || 144 || 서버측 입력검증 || 미흡 || 확장자·크기 중심 검증, URL·Host·Origin 통제 부족 ||
145 || 출력 안전성 || 미흡 || raw textarea, JS 문자열, `innerHTML` 재구성 경로 다수 || 145 || 출력 안전성 || 미흡 || raw textarea, JS 문자열, `innerHTML` 재구성 경로 다수 ||
146 || 업로드 경계 || 미흡 || MIME/매직바이트 검증 부재, 이미지 자원 제한 부재 || 146 || 업로드 경계 || 미흡 || MIME/매직바이트 검증 부재, 이미지 자원 제한 부재 ||
147 || 협업 보조 엔드포인트 || 주의 || 파일권한·CORS·정리 로직 불일치 존재 || 147 || 협업 보조 엔드포인트 || 주의 || 파일권한·CORS·정리 로직 불일치 존재 ||
148 || 운영 호환성 || 보통 || 경로 자동 계산은 있으나 Host 신뢰가 과도함 || 148 || 운영 호환성 || 보통 || 경로 자동 계산은 있으나 Host 신뢰가 과도함 ||
149 || 외부 공개 서비스 적합성 || '''조건부 부적정''' || 보안 선행 보완 없이는 공개 운영 비권고 || 149 || 외부 공개 서비스 적합성 || '''조건부 부적정''' || 보안 선행 보완 없이는 공개 운영 비권고 ||
150   150  
151 == 5. 주요 강점 == 151 == 5. 주요 강점 ==
152   152  
153 - 전체 PHP 파일 13개에 대해 문법 오류가 확인되지 않았다. 153 - 전체 PHP 파일 13개에 대해 문법 오류가 확인되지 않았다.
154 - 이미지 업로드 경로에서 `getimagesize()` 기반 실제 이미지 여부 확인은 수행한다. 154 - 이미지 업로드 경로에서 `getimagesize()` 기반 실제 이미지 여부 확인은 수행한다.
155 - 협업 기능은 `flock()` 기반 잠금과 원자적 JSON 업데이트 구조를 일부 도입하고 있다. 155 - 협업 기능은 `flock()` 기반 잠금과 원자적 JSON 업데이트 구조를 일부 도입하고 있다.
156 - PDF 뷰어와 코드 블럭, 테이블, 파일 블럭 등 기능 모듈화는 비교적 명확하다. 156 - PDF 뷰어와 코드 블럭, 테이블, 파일 블럭 등 기능 모듈화는 비교적 명확하다.
157 - 라이선스/버전 정보와 기본 플러그인 우선순위 관리 구조는 일관적이다. 157 - 라이선스/버전 정보와 기본 플러그인 우선순위 관리 구조는 일관적이다.
158   158  
159 == 6. 세부 감사 결과 == 159 == 6. 세부 감사 결과 ==
160   160  
161 === 6.1 Critical === 161 === 6.1 Critical ===
162   162  
163 ||= 식별자 ||= 위험도 ||= 위치 ||= 판정 ||= 요약 || 163 ||= 식별자 ||= 위험도 ||= 위치 ||= 판정 ||= 요약 ||
164 || F-01 || Critical || `editor.lib.php` || 미조치 || 본문 내용과 ID 값이 HTML/JS 문맥에 직접 삽입되어 구조 파손 및 XSS 가능성이 존재함 || 164 || F-01 || Critical || `editor.lib.php` || 미조치 || 본문 내용과 ID 값이 HTML/JS 문맥에 직접 삽입되어 구조 파손 및 XSS 가능성이 존재함 ||
165 || F-02 || Critical || `js/core.js` || 미조치 || 붙여넣기 및 sanitizer가 `innerHTML`과 얕은 allowlist에 의존하여 DOM XSS 우회 가능성이 큼 || 165 || F-02 || Critical || `js/core.js` || 미조치 || 붙여넣기 및 sanitizer가 `innerHTML`과 얕은 allowlist에 의존하여 DOM XSS 우회 가능성이 큼 ||
166   166  
167 ==== F-01. 본문 로딩/저장 경계의 직접 출력 ==== 167 ==== F-01. 본문 로딩/저장 경계의 직접 출력 ====
168 - `editor.lib.php:289-295`에서 본문을 JS 문자열로 가공하나 `</script>` 조기 종료와 컨텍스트 분리가 충분하지 않다. 168 - `editor.lib.php:289-295`에서 본문을 JS 문자열로 가공하나 `</script>` 조기 종료와 컨텍스트 분리가 충분하지 않다.
169 - `editor.lib.php:494-495`에서 hidden textarea에 `$id`, `$content`를 그대로 출력한다. 169 - `editor.lib.php:494-495`에서 hidden textarea에 `$id`, `$content`를 그대로 출력한다.
170 - `editor.lib.php:528-535`에서 `window.<id>_editor` 및 `tempDiv.innerHTML = contentToLoad`를 직접 수행한다. 170 - `editor.lib.php:528-535`에서 `window.<id>_editor` 및 `tempDiv.innerHTML = contentToLoad`를 직접 수행한다.
171 - `editor.lib.php:584`에서도 일반 textarea 경로에 본문을 그대로 출력한다. 171 - `editor.lib.php:584`에서도 일반 textarea 경로에 본문을 그대로 출력한다.
172 - `editor.lib.php:595-597`에서 저장 직전 다시 `innerHTML` 재구성을 수행한다. 172 - `editor.lib.php:595-597`에서 저장 직전 다시 `innerHTML` 재구성을 수행한다.
173   173  
174 '''감사의견'''[br] 174 '''감사의견'''[br]
175 본문 또는 필드 ID가 신뢰되지 않는 경로에서 유입될 경우 DOM 파손, 스크립트 블록 조기 종료, HTML 속성 탈출, 저장 시 이차적 구조 오염으로 이어질 수 있다. 본 항목은 패키지의 핵심 출력 경계에 해당하므로 우선순위가 가장 높다. 175 본문 또는 필드 ID가 신뢰되지 않는 경로에서 유입될 경우 DOM 파손, 스크립트 블록 조기 종료, HTML 속성 탈출, 저장 시 이차적 구조 오염으로 이어질 수 있다. 본 항목은 패키지의 핵심 출력 경계에 해당하므로 우선순위가 가장 높다.
176   176  
177 ==== F-02. 코어 sanitizer 및 붙여넣기 경계의 구조적 취약 ==== 177 ==== F-02. 코어 sanitizer 및 붙여넣기 경계의 구조적 취약 ====
178 - `js/core.js:493-517`에서 붙여넣기 내용을 `tempDiv.innerHTML`로 해석한 후 `currentBlock.innerHTML = beforeText + sanitizedHTML + afterText` 방식으로 다시 삽입한다. 178 - `js/core.js:493-517`에서 붙여넣기 내용을 `tempDiv.innerHTML`로 해석한 후 `currentBlock.innerHTML = beforeText + sanitizedHTML + afterText` 방식으로 다시 삽입한다.
179 - `js/core.js:2078-2103`의 `sanitizeHTML()`은 `href`, `src`, `style`을 허용하면서 프로토콜 및 스타일 값 검증을 하지 않는다. 179 - `js/core.js:2078-2103`의 `sanitizeHTML()`은 `href`, `src`, `style`을 허용하면서 프로토콜 및 스타일 값 검증을 하지 않는다.
180 - `allowedTags`에는 `a`, `img`, `span`, `div` 등이 포함되어 있어 속성 조합 우회 가능성이 존재한다. 180 - `allowedTags`에는 `a`, `img`, `span`, `div` 등이 포함되어 있어 속성 조합 우회 가능성이 존재한다.
181   181  
182 '''감사의견'''[br] 182 '''감사의견'''[br]
183 전형적인 “수제 sanitizer” 구조이며, 프로토콜·CSS·이벤트 간접 주입을 방어하기에 부족하다. 특히 붙여넣기 경계는 외부 HTML이 대량 유입되는 지점이므로, 실제 서비스 환경에서는 DOMPurify급 검증기로 교체하는 편이 타당하다. 183 전형적인 “수제 sanitizer” 구조이며, 프로토콜·CSS·이벤트 간접 주입을 방어하기에 부족하다. 특히 붙여넣기 경계는 외부 HTML이 대량 유입되는 지점이므로, 실제 서비스 환경에서는 DOMPurify급 검증기로 교체하는 편이 타당하다.
184   184  
185 === 6.2 High === 185 === 6.2 High ===
186   186  
187 ||= 식별자 ||= 위험도 ||= 위치 ||= 판정 ||= 요약 || 187 ||= 식별자 ||= 위험도 ||= 위치 ||= 판정 ||= 요약 ||
188 || F-03 || High || `plugin/video/video_view.php` || 미조치 || 외부 URL 및 상대경로를 충분히 제한하지 않아 비디오 뷰어가 비허용 URL을 그대로 렌더링할 수 있음 || 188 || F-03 || High || `plugin/video/video_view.php` || 미조치 || 외부 URL 및 상대경로를 충분히 제한하지 않아 비디오 뷰어가 비허용 URL을 그대로 렌더링할 수 있음 ||
189 || F-04 || High || `config/upload_config.php`, `plugin/file/file_upload.php`, `plugin/image/image_upload.php` || 미조치 || 업로드 검증이 실질적으로 확장자·크기 중심이며 MIME/매직바이트 검증이 없음 || 189 || F-04 || High || `config/upload_config.php`, `plugin/file/file_upload.php`, `plugin/image/image_upload.php` || 미조치 || 업로드 검증이 실질적으로 확장자·크기 중심이며 MIME/매직바이트 검증이 없음 ||
190 || F-05 || High || `plugin/file/file.js`, `plugin/video/video.js`, `plugin/table/table.js` || 미조치 || 파일명/URL/클립보드 HTML이 `innerHTML`로 재삽입되어 XSS 공격면이 존재함 || 190 || F-05 || High || `plugin/file/file.js`, `plugin/video/video.js`, `plugin/table/table.js` || 미조치 || 파일명/URL/클립보드 HTML이 `innerHTML`로 재삽입되어 XSS 공격면이 존재함 ||
191 || F-06 || High || `config/t2_config.php` || 미조치 || `HTTP_HOST`를 검증 없이 신뢰하여 URL 계산에 사용함 || 191 || F-06 || High || `config/t2_config.php` || 미조치 || `HTTP_HOST`를 검증 없이 신뢰하여 URL 계산에 사용함 ||
192 || F-07 || High || `plugin/image/image_upload.php` || 미조치 || 무제한 메모리/실행시간 설정으로 자원 고갈 위험이 큼 || 192 || F-07 || High || `plugin/image/image_upload.php` || 미조치 || 무제한 메모리/실행시간 설정으로 자원 고갈 위험이 큼 ||
193   193  
194 ==== F-03. 비디오 뷰어의 외부 URL 통과 및 경로 검증 부재 ==== 194 ==== F-03. 비디오 뷰어의 외부 URL 통과 및 경로 검증 부재 ====
195 - `plugin/video/video_view.php:8-19`에서 `$_GET['video']`를 받아 `http`로 시작하지 않으면 절대경로로 변환한다. 195 - `plugin/video/video_view.php:8-19`에서 `$_GET['video']`를 받아 `http`로 시작하지 않으면 절대경로로 변환한다.
196 - 즉, `http://`, `https://` 형태의 외부 URL은 그대로 통과한다. 196 - 즉, `http://`, `https://` 형태의 외부 URL은 그대로 통과한다.
197 - `plugin/video/video_view.php:24-26`은 확장자만 확인하고, 실제 허용 도메인 또는 데이터 디렉터리 하위 여부를 검증하지 않는다. 197 - `plugin/video/video_view.php:24-26`은 확장자만 확인하고, 실제 허용 도메인 또는 데이터 디렉터리 하위 여부를 검증하지 않는다.
198   198  
199 '''감사의견'''[br] 199 '''감사의견'''[br]
200 브라우저 기준의 외부 요청 유발, 핫링킹, 예기치 않은 제3자 호스트 렌더링, 상대경로 오염 가능성이 있다. 비디오 뷰어는 same-origin 또는 명시적 allowlist 기반으로 제한해야 한다. 200 브라우저 기준의 외부 요청 유발, 핫링킹, 예기치 않은 제3자 호스트 렌더링, 상대경로 오염 가능성이 있다. 비디오 뷰어는 same-origin 또는 명시적 allowlist 기반으로 제한해야 한다.
201   201  
202 ==== F-04. 업로드 경계의 실질 검증 부재 ==== 202 ==== F-04. 업로드 경계의 실질 검증 부재 ====
203 - `config/upload_config.php:138-156`의 `validate_upload_file()`는 확장자와 파일 크기만 검사한다. 203 - `config/upload_config.php:138-156`의 `validate_upload_file()`는 확장자와 파일 크기만 검사한다.
204 - `plugin/file/file_upload.php:47-50`은 해당 함수를 그대로 사용한다. 204 - `plugin/file/file_upload.php:47-50`은 해당 함수를 그대로 사용한다.
205 - `plugin/image/image_upload.php:72-76` 역시 같은 함수를 호출하나, 본질적으로 확장자·크기 확인에 머문다. 205 - `plugin/image/image_upload.php:72-76` 역시 같은 함수를 호출하나, 본질적으로 확장자·크기 확인에 머문다.
206 - 스팟 테스트 결과 `validate_upload_file('fake.mp4', 100, 'video')`는 성공을 반환하였다. 206 - 스팟 테스트 결과 `validate_upload_file('fake.mp4', 100, 'video')`는 성공을 반환하였다.
207   207  
208 '''감사의견'''[br] 208 '''감사의견'''[br]
209 현재 구조는 위장 확장자, 내용 불일치 파일, 악성 샘플에 취약하다. 최소한 MIME, 매직바이트, 이미지 픽셀 한도, 업로드 실패 원인 세분화가 필요하다. 209 현재 구조는 위장 확장자, 내용 불일치 파일, 악성 샘플에 취약하다. 최소한 MIME, 매직바이트, 이미지 픽셀 한도, 업로드 실패 원인 세분화가 필요하다.
210   210  
211 ==== F-05. 플러그인별 HTML 재삽입 경계 ==== 211 ==== F-05. 플러그인별 HTML 재삽입 경계 ====
212 - `plugin/file/file.js:683-729`은 `fileInfo.url`, `fileInfo.original_name`을 오디오/일반 파일 블럭 `innerHTML`에 직접 삽입한다. 212 - `plugin/file/file.js:683-729`은 `fileInfo.url`, `fileInfo.original_name`을 오디오/일반 파일 블럭 `innerHTML`에 직접 삽입한다.
213 - `plugin/video/video.js:269-279`은 업로드 후 미리보기에서 `data.file.url`, `file.name`을 그대로 사용한다. 213 - `plugin/video/video.js:269-279`은 업로드 후 미리보기에서 `data.file.url`, `file.name`을 그대로 사용한다.
214 - `plugin/video/video.js:561-565`는 URL 수정 모달의 `value="${currentUrl}"`에 현재 URL을 그대로 넣는다. 214 - `plugin/video/video.js:561-565`는 URL 수정 모달의 `value="${currentUrl}"`에 현재 URL을 그대로 넣는다.
215 - `plugin/table/table.js:20-26`은 클립보드 HTML에서 `table`을 `cloneNode(true)`로 복사하나, 이벤트 속성 제거가 없다. 215 - `plugin/table/table.js:20-26`은 클립보드 HTML에서 `table`을 `cloneNode(true)`로 복사하나, 이벤트 속성 제거가 없다.
216   216  
217 '''감사의견'''[br] 217 '''감사의견'''[br]
218 서버 응답, 파일명, 클립보드 HTML을 신뢰하는 구조다. 업로드 응답이 오염되거나 사용자가 악성 파일명·테이블 HTML을 다루는 환경에서는 DOM XSS가 가능하다. 218 서버 응답, 파일명, 클립보드 HTML을 신뢰하는 구조다. 업로드 응답이 오염되거나 사용자가 악성 파일명·테이블 HTML을 다루는 환경에서는 DOM XSS가 가능하다.
219   219  
220 ==== F-06. Host Header 신뢰 ==== 220 ==== F-06. Host Header 신뢰 ====
221 - `config/t2_config.php:25-35`에서 `$_SERVER['HTTP_HOST']`를 그대로 `T2EDITOR_URL` 계산에 사용한다. 221 - `config/t2_config.php:25-35`에서 `$_SERVER['HTTP_HOST']`를 그대로 `T2EDITOR_URL` 계산에 사용한다.
222 - 스팟 테스트 결과 악성 Host 문자열이 URL 상수에 그대로 반영되었다. 222 - 스팟 테스트 결과 악성 Host 문자열이 URL 상수에 그대로 반영되었다.
223   223  
224 '''감사의견'''[br] 224 '''감사의견'''[br]
225 역프록시 설정이 약하거나 Host 헤더 검증이 없는 배포 환경에서는 링크·리소스 경로 위변조가 가능하다. Host는 allowlist 또는 정규식 검증 후 사용해야 한다. 225 역프록시 설정이 약하거나 Host 헤더 검증이 없는 배포 환경에서는 링크·리소스 경로 위변조가 가능하다. Host는 allowlist 또는 정규식 검증 후 사용해야 한다.
226   226  
227 ==== F-07. 이미지 처리 자원 한도 부재 ==== 227 ==== F-07. 이미지 처리 자원 한도 부재 ====
228 - `plugin/image/image_upload.php:8-9`에서 `memory_limit = -1`, `max_execution_time = 0`을 설정한다. 228 - `plugin/image/image_upload.php:8-9`에서 `memory_limit = -1`, `max_execution_time = 0`을 설정한다.
229 - 이미지 크기·픽셀 수·예상 메모리 사용량을 제한하지 않는다. 229 - 이미지 크기·픽셀 수·예상 메모리 사용량을 제한하지 않는다.
230   230  
231 '''감사의견'''[br] 231 '''감사의견'''[br]
232 고해상도 이미지, 손상된 이미지, 압축폭탄 계열 샘플에서 과도한 자원 사용이 발생할 수 있다. 이미지 업로드는 별도 상한, 픽셀 제한, WebP 변환 실패 정책을 가져야 한다. 232 고해상도 이미지, 손상된 이미지, 압축폭탄 계열 샘플에서 과도한 자원 사용이 발생할 수 있다. 이미지 업로드는 별도 상한, 픽셀 제한, WebP 변환 실패 정책을 가져야 한다.
233   233  
234 === 6.3 Medium === 234 === 6.3 Medium ===
235   235  
236 ||= 식별자 ||= 위험도 ||= 위치 ||= 판정 ||= 요약 || 236 ||= 식별자 ||= 위험도 ||= 위치 ||= 판정 ||= 요약 ||
237 || F-08 || Medium || `config/get_upload_config.php` || 미조치 || 설정 조회 엔드포인트가 `Access-Control-Allow-Origin: *`로 공개됨 || 237 || F-08 || Medium || `config/get_upload_config.php` || 미조치 || 설정 조회 엔드포인트가 `Access-Control-Allow-Origin: *`로 공개됨 ||
238 || F-09 || Medium || `plugin/collab/collab_number_delete.php`, `plugin/collab/collab_number.php` || 미조치 || 협업 정리 엔드포인트에 CORS 전역 허용과 파일명 불일치가 공존함 || 238 || F-09 || Medium || `plugin/collab/collab_number_delete.php`, `plugin/collab/collab_number.php` || 미조치 || 협업 정리 엔드포인트에 CORS 전역 허용과 파일명 불일치가 공존함 ||
239 || F-10 || Medium || `plugin/collab/collab_verification.php`, `plugin/collab/collab_number.php` || 미조치 || 707/0666 수준의 파일권한 가이드 및 실제 `chmod` 사용이 보안상 과도함 || 239 || F-10 || Medium || `plugin/collab/collab_verification.php`, `plugin/collab/collab_number.php` || 미조치 || 707/0666 수준의 파일권한 가이드 및 실제 `chmod` 사용이 보안상 과도함 ||
240 || F-11 || Medium || `js/core.js`, `plugin/code/code.js`, `plugin/table/table.js` || 미조치 || `execCommand`, `queryCommandState`, `DOMNodeInserted` 등 구식 API 의존도가 높아 호환성 및 안정성 리스크가 존재함 || 240 || F-11 || Medium || `js/core.js`, `plugin/code/code.js`, `plugin/table/table.js` || 미조치 || `execCommand`, `queryCommandState`, `DOMNodeInserted` 등 구식 API 의존도가 높아 호환성 및 안정성 리스크가 존재함 ||
241 || F-12 || Medium || `plugin/ai/*.js`, `plugin/clipurl/clipurl.js`, `editor.lib.php` || 미조치 || 외부 서비스 및 외부 폰트 의존성이 기본값으로 포함됨 || 241 || F-12 || Medium || `plugin/ai/*.js`, `plugin/clipurl/clipurl.js`, `editor.lib.php` || 미조치 || 외부 서비스 및 외부 폰트 의존성이 기본값으로 포함됨 ||
242   242  
243 ==== F-08. 설정 조회 엔드포인트의 전역 CORS ==== 243 ==== F-08. 설정 조회 엔드포인트의 전역 CORS ====
244 - `config/get_upload_config.php:4-7`은 `Access-Control-Allow-Origin: *`와 `GET` 허용을 직접 설정한다. 244 - `config/get_upload_config.php:4-7`은 `Access-Control-Allow-Origin: *`와 `GET` 허용을 직접 설정한다.
245 - 제공 정보가 비밀 값은 아니나, 설치 환경별 허용 확장자·용량 정책이 제3자에 노출된다. 245 - 제공 정보가 비밀 값은 아니나, 설치 환경별 허용 확장자·용량 정책이 제3자에 노출된다.
246   246  
247 '''감사의견'''[br] 247 '''감사의견'''[br]
248 중대한 침해 경로는 아니지만, 동일정책 통일 측면에서 불필요한 전역 CORS는 제거하는 편이 타당하다. 248 중대한 침해 경로는 아니지만, 동일정책 통일 측면에서 불필요한 전역 CORS는 제거하는 편이 타당하다.
249   249  
250 ==== F-09. 협업 정리 엔드포인트의 CORS 및 파일명 불일치 ==== 250 ==== F-09. 협업 정리 엔드포인트의 CORS 및 파일명 불일치 ====
251 - `plugin/collab/collab_number_delete.php:17-19`는 `Access-Control-Allow-Origin: *`를 허용한다. 251 - `plugin/collab/collab_number_delete.php:17-19`는 `Access-Control-Allow-Origin: *`를 허용한다.
252 - `plugin/collab/collab_number.php:243-250`은 `client_ops` 파일을 생성한다. 252 - `plugin/collab/collab_number.php:243-250`은 `client_ops` 파일을 생성한다.
253 - 그러나 `plugin/collab/collab_number_delete.php:57-65`, `101`은 삭제 대상에 `ops` 파일을 사용한다. 253 - 그러나 `plugin/collab/collab_number_delete.php:57-65`, `101`은 삭제 대상에 `ops` 파일을 사용한다.
254   254  
255 '''감사의견'''[br] 255 '''감사의견'''[br]
256 host_token 검증이 존재하므로 즉시 삭제 취약점으로 보기는 어렵다. 다만 파일명 불일치로 인한 정리 누락, CORS 확대, 운영 혼선을 유발하므로 개선이 필요하다. 256 host_token 검증이 존재하므로 즉시 삭제 취약점으로 보기는 어렵다. 다만 파일명 불일치로 인한 정리 누락, CORS 확대, 운영 혼선을 유발하므로 개선이 필요하다.
257   257  
258 ==== F-10. 협업 기능의 과도한 권한 가이드 ==== 258 ==== F-10. 협업 기능의 과도한 권한 가이드 ====
259 - `plugin/collab/collab_verification.php:34`, `64`는 `/collab` 디렉터리에 707 권한 부여를 안내한다. 259 - `plugin/collab/collab_verification.php:34`, `64`는 `/collab` 디렉터리에 707 권한 부여를 안내한다.
260 - `plugin/collab/collab_number.php:59`, `71`은 생성 파일에 `0666` 권한을 부여한다. 260 - `plugin/collab/collab_number.php:59`, `71`은 생성 파일에 `0666` 권한을 부여한다.
261   261  
262 '''감사의견'''[br] 262 '''감사의견'''[br]
263 공유 호스팅이나 다중 사용자 환경에서는 과도한 권한 설정이 부적절하다. 운영 환경에 맞춘 최소 권한 원칙으로 재설계해야 한다. 263 공유 호스팅이나 다중 사용자 환경에서는 과도한 권한 설정이 부적절하다. 운영 환경에 맞춘 최소 권한 원칙으로 재설계해야 한다.
264   264  
265 ==== F-11. 구식 DOM 편집 API 의존 ==== 265 ==== F-11. 구식 DOM 편집 API 의존 ====
266 - `js/core.js`는 `DOMNodeInserted`, `queryCommandState`, `document.execCommand()`에 크게 의존한다. 266 - `js/core.js`는 `DOMNodeInserted`, `queryCommandState`, `document.execCommand()`에 크게 의존한다.
267 - `plugin/code/code.js`, `plugin/table/table.js`, `plugin/collab/collab.js`도 같은 계열 API를 사용한다. 267 - `plugin/code/code.js`, `plugin/table/table.js`, `plugin/collab/collab.js`도 같은 계열 API를 사용한다.
268   268  
269 '''감사의견'''[br] 269 '''감사의견'''[br]
270 즉시 보안 취약점은 아니지만, 브라우저별 동작 차이와 유지보수 비용이 매우 크다. 9.x 이후 버전에서는 Selection/Range 기반으로 단계적 이행이 필요하다. 270 즉시 보안 취약점은 아니지만, 브라우저별 동작 차이와 유지보수 비용이 매우 크다. 9.x 이후 버전에서는 Selection/Range 기반으로 단계적 이행이 필요하다.
271   271  
272 ==== F-12. 외부 서비스·외부 폰트 하드 의존 ==== 272 ==== F-12. 외부 서비스·외부 폰트 하드 의존 ====
273 - `editor.lib.php:330-331`은 Google Fonts를 직접 호출한다. 273 - `editor.lib.php:330-331`은 Google Fonts를 직접 호출한다.
274 - `editor.lib.php:498`, `readme.txt`는 dsclub 링크를 포함한다. 274 - `editor.lib.php:498`, `readme.txt`는 dsclub 링크를 포함한다.
275 - `plugin/ai/ai.js`, `plugin/ai_rearrange/ai_rearrange.js`, `plugin/clipurl/clipurl.js`는 외부 API 엔드포인트를 기본값으로 가진다. 275 - `plugin/ai/ai.js`, `plugin/ai_rearrange/ai_rearrange.js`, `plugin/clipurl/clipurl.js`는 외부 API 엔드포인트를 기본값으로 가진다.
276   276  
277 '''감사의견'''[br] 277 '''감사의견'''[br]
278 기능상 의존성일 뿐 즉시 취약점은 아니다. 다만 사내망·폐쇄망 환경, 개인정보·정책 통제 환경에서는 외부 호출 정책을 분리할 필요가 있다. 278 기능상 의존성일 뿐 즉시 취약점은 아니다. 다만 사내망·폐쇄망 환경, 개인정보·정책 통제 환경에서는 외부 호출 정책을 분리할 필요가 있다.
279   279  
280 === 6.4 Low === 280 === 6.4 Low ===
281   281  
282 ||= 식별자 ||= 위험도 ||= 위치 ||= 판정 ||= 요약 || 282 ||= 식별자 ||= 위험도 ||= 위치 ||= 판정 ||= 요약 ||
283 || F-13 || Low || `plugin/file/pdf_view.php` || 부분 양호 || 입력 포맷 검증이 일부 존재하나 구조적 일관성은 부족 || 283 || F-13 || Low || `plugin/file/pdf_view.php` || 부분 양호 || 입력 포맷 검증이 일부 존재하나 구조적 일관성은 부족 ||
284 || F-14 || Low || `readme.txt`, `editor.lib.php` || 양호 || 라이선스/버전 표시는 존재하나 런타임 검증 효과는 제한적 || 284 || F-14 || Low || `readme.txt`, `editor.lib.php` || 양호 || 라이선스/버전 표시는 존재하나 런타임 검증 효과는 제한적 ||
285   285  
286 == 7. 문법 검사 및 스팟 테스트 == 286 == 7. 문법 검사 및 스팟 테스트 ==
287   287  
288 ### 7.1 PHP 문법 검사 288 ### 7.1 PHP 문법 검사
289 아래 PHP 파일 13개에 대해 `php -l` 검사 결과 문법 오류는 확인되지 않았다. 289 아래 PHP 파일 13개에 대해 `php -l` 검사 결과 문법 오류는 확인되지 않았다.
290 - `t2_css_min.php` 290 - `t2_css_min.php`
291 - `config/t2_config.php` 291 - `config/t2_config.php`
292 - `config/upload_config.php` 292 - `config/upload_config.php`
293 - `config/get_upload_config.php` 293 - `config/get_upload_config.php`
294 - `t2_js_min.php` 294 - `t2_js_min.php`
295 - `plugin/video/video_view.php` 295 - `plugin/video/video_view.php`
296 - `plugin/file/pdf_view.php` 296 - `plugin/file/pdf_view.php`
297 - `plugin/file/file_upload.php` 297 - `plugin/file/file_upload.php`
298 - `plugin/image/image_upload.php` 298 - `plugin/image/image_upload.php`
299 - `plugin/collab/collab_verification.php` 299 - `plugin/collab/collab_verification.php`
300 - `plugin/collab/collab_number_delete.php` 300 - `plugin/collab/collab_number_delete.php`
301 - `plugin/collab/collab_number.php` 301 - `plugin/collab/collab_number.php`
302 - `editor.lib.php` 302 - `editor.lib.php`
303   303  
304 ### 7.2 스팟 테스트 결과 304 ### 7.2 스팟 테스트 결과
305 ||= 테스트 ||= 결과 ||= 의미 || 305 ||= 테스트 ||= 결과 ||= 의미 ||
306 || `T2EDITOR_URL` Host 반영 테스트 || 취약 재현 || 악성 `HTTP_HOST` 값이 URL 상수에 직접 반영됨 || 306 || `T2EDITOR_URL` Host 반영 테스트 || 취약 재현 || 악성 `HTTP_HOST` 값이 URL 상수에 직접 반영됨 ||
307 || `validate_upload_file('fake.mp4', 100, 'video')` || 성공 반환 || 내용 검증 없이 확장자·크기만 통과함 || 307 || `validate_upload_file('fake.mp4', 100, 'video')` || 성공 반환 || 내용 검증 없이 확장자·크기만 통과함 ||
308 || 정적 스캔: `innerHTML =` || 181건 || 공격면이 넓고 수제 sanitization 의존도가 큼 || 308 || 정적 스캔: `innerHTML =` || 181건 || 공격면이 넓고 수제 sanitization 의존도가 큼 ||
309 || 정적 스캔: `Access-Control-Allow-Origin: *` || 2건 || 설정 조회와 협업 삭제 엔드포인트에 전역 CORS 존재 || 309 || 정적 스캔: `Access-Control-Allow-Origin: *` || 2건 || 설정 조회와 협업 삭제 엔드포인트에 전역 CORS 존재 ||
310   310  
311 == 8. 보완 우선순위 == 311 == 8. 보완 우선순위 ==
312   312  
313 ### 8.1 즉시 보완 권고(배포 전) 313 ### 8.1 즉시 보완 권고(배포 전)
314 1. `editor.lib.php` 314 1. `editor.lib.php`
315 - hidden textarea 및 JS bootstrap 경계의 `htmlspecialchars()`, `json_encode()`, safe id 분리 적용 315 - hidden textarea 및 JS bootstrap 경계의 `htmlspecialchars()`, `json_encode()`, safe id 분리 적용
316 - `</script>` 조기 종료 방어 포함 316 - `</script>` 조기 종료 방어 포함
317 2. `js/core.js` 317 2. `js/core.js`
318 - 붙여넣기 sanitizer를 검증된 라이브러리로 교체 318 - 붙여넣기 sanitizer를 검증된 라이브러리로 교체
319 - `href/src/style` 프로토콜·CSS 화이트리스트 적용 319 - `href/src/style` 프로토콜·CSS 화이트리스트 적용
320 3. `plugin/video/video_view.php` 320 3. `plugin/video/video_view.php`
321 - 외부 URL 직접 허용 제거 321 - 외부 URL 직접 허용 제거
322 - same-origin 또는 allowlist 도메인만 허용 322 - same-origin 또는 allowlist 도메인만 허용
323 - `realpath()` 기반 경로 포함 검증 추가 323 - `realpath()` 기반 경로 포함 검증 추가
324 4. `config/upload_config.php` 및 업로드 엔드포인트 324 4. `config/upload_config.php` 및 업로드 엔드포인트
325 - MIME/매직바이트/픽셀 수 검증 추가 325 - MIME/매직바이트/픽셀 수 검증 추가
326 - 파일명 정제 및 저장명 난수화 적용 326 - 파일명 정제 및 저장명 난수화 적용
327 5. `plugin/image/image_upload.php` 327 5. `plugin/image/image_upload.php`
328 - `memory_limit`, `max_execution_time` 상한 설정 328 - `memory_limit`, `max_execution_time` 상한 설정
329 - SVG/ICO 처리정책 명확화 329 - SVG/ICO 처리정책 명확화
330   330  
331 ### 8.2 단기 보완 권고(배포 직후) 331 ### 8.2 단기 보완 권고(배포 직후)
332 1. `config/t2_config.php` Host 검증 추가 332 1. `config/t2_config.php` Host 검증 추가
333 2. `config/get_upload_config.php` 전역 CORS 제거 333 2. `config/get_upload_config.php` 전역 CORS 제거
334 3. `plugin/file/file.js`, `plugin/video/video.js`, `plugin/table/table.js`의 표시값/URL/클립보드 HTML 이스케이프 적용 334 3. `plugin/file/file.js`, `plugin/video/video.js`, `plugin/table/table.js`의 표시값/URL/클립보드 HTML 이스케이프 적용
335 4. `plugin/collab/collab_number_delete.php` 파일명 체계 `client_ops`와 일치화 335 4. `plugin/collab/collab_number_delete.php` 파일명 체계 `client_ops`와 일치화
336 5. 협업 디렉터리 권한 정책 최소권한 원칙으로 변경 336 5. 협업 디렉터리 권한 정책 최소권한 원칙으로 변경
337   337  
338 ### 8.3 중기 보완 권고 338 ### 8.3 중기 보완 권고
339 1. `execCommand`, `queryCommandState`, `DOMNodeInserted` 의존 제거 339 1. `execCommand`, `queryCommandState`, `DOMNodeInserted` 의존 제거
340 2. 외부 서비스 의존 기능의 on/off 설정 분리 340 2. 외부 서비스 의존 기능의 on/off 설정 분리
341 3. 런타임 minify PHP(`t2_css_min.php`, `t2_js_min.php`)를 빌드 타임 산출물로 전환 341 3. 런타임 minify PHP(`t2_css_min.php`, `t2_js_min.php`)를 빌드 타임 산출물로 전환
342   342  
343 == 9. 최종 감사 의견 == 343 == 9. 최종 감사 의견 ==
344   344  
345 [warning(최종 판정)] 345 [warning(최종 판정)]
346 T2Editor 9.1.1은 기능적 완성도는 높으나, 외부 공개 서비스 기준으로는 그대로 배포하기에 부적절한 항목이 다수 확인되었다. 특히 본문 출력 경계, 붙여넣기 sanitizer, 업로드 검증, 비디오 뷰어, Host 신뢰 경계는 선행 보완이 필요하다. 따라서 본 감사는 '''조건부 부적정''' 의견을 제시한다. 346 T2Editor 9.1.1은 기능적 완성도는 높으나, 외부 공개 서비스 기준으로는 그대로 배포하기에 부적절한 항목이 다수 확인되었다. 특히 본문 출력 경계, 붙여넣기 sanitizer, 업로드 검증, 비디오 뷰어, Host 신뢰 경계는 선행 보완이 필요하다. 따라서 본 감사는 '''조건부 부적정''' 의견을 제시한다.
347 [/warning] 347 [/warning]
348   348  
349 ### 9.1 판단 이유 349 ### 9.1 판단 이유
350 - 에디터 핵심 경계에 직접 출력 및 `innerHTML` 재구성 경로가 다수 존재함 350 - 에디터 핵심 경계에 직접 출력 및 `innerHTML` 재구성 경로가 다수 존재함
351 - 업로드 검증이 확장자/크기 수준에 머물러 우회에 취약함 351 - 업로드 검증이 확장자/크기 수준에 머물러 우회에 취약함
352 - 외부 URL 통제 및 Host 검증이 부재함 352 - 외부 URL 통제 및 Host 검증이 부재함
353 - 협업 보조 엔드포인트에 CORS/권한/정리 불일치가 존재함 353 - 협업 보조 엔드포인트에 CORS/권한/정리 불일치가 존재함
354   354  
355 ### 9.2 배포 권고 355 ### 9.2 배포 권고
356 - '''내부 시험 운영: 가능''' 356 - '''내부 시험 운영: 가능'''
357 - '''폐쇄망·신뢰 사용자 환경: 제한적 가능''' 357 - '''폐쇄망·신뢰 사용자 환경: 제한적 가능'''
358 - '''외부 공개 서비스: 보안 보완 선행 후 재감사 권고''' 358 - '''외부 공개 서비스: 보안 보완 선행 후 재감사 권고'''
359   359  
360 == 10. 부록 == 360 == 10. 부록 ==
361   361  
362 [folding(주요 근거 라인)] 362 [folding(주요 근거 라인)]
363 - `config/t2_config.php:25-35` 363 - `config/t2_config.php:25-35`
364 - `config/upload_config.php:138-156` 364 - `config/upload_config.php:138-156`
365 - `config/get_upload_config.php:4-17` 365 - `config/get_upload_config.php:4-17`
366 - `editor.lib.php:289-295` 366 - `editor.lib.php:289-295`
367 - `editor.lib.php:494-495` 367 - `editor.lib.php:494-495`
368 - `editor.lib.php:528-535` 368 - `editor.lib.php:528-535`
369 - `editor.lib.php:584` 369 - `editor.lib.php:584`
370 - `editor.lib.php:595-597` 370 - `editor.lib.php:595-597`
371 - `js/core.js:493-517` 371 - `js/core.js:493-517`
372 - `js/core.js:2078-2103` 372 - `js/core.js:2078-2103`
373 - `plugin/file/file_upload.php:20-24` 373 - `plugin/file/file_upload.php:20-24`
374 - `plugin/file/file_upload.php:47-57` 374 - `plugin/file/file_upload.php:47-57`
375 - `plugin/image/image_upload.php:8-9` 375 - `plugin/image/image_upload.php:8-9`
376 - `plugin/image/image_upload.php:72-76` 376 - `plugin/image/image_upload.php:72-76`
377 - `plugin/video/video_view.php:8-19` 377 - `plugin/video/video_view.php:8-19`
378 - `plugin/file/file.js:683-729` 378 - `plugin/file/file.js:683-729`
379 - `plugin/video/video.js:269-279` 379 - `plugin/video/video.js:269-279`
380 - `plugin/video/video.js:561-565` 380 - `plugin/video/video.js:561-565`
381 - `plugin/table/table.js:20-26` 381 - `plugin/table/table.js:20-26`
382 - `plugin/collab/collab_number.php:243-250` 382 - `plugin/collab/collab_number.php:243-250`
383 - `plugin/collab/collab_number_delete.php:17-19` 383 - `plugin/collab/collab_number_delete.php:17-19`
384 - `plugin/collab/collab_number_delete.php:57-65` 384 - `plugin/collab/collab_number_delete.php:57-65`
385 [/folding] 385 [/folding]
386   386  
T2WIKI · 기술 통합 위키 & 프로젝트 허브 · 나무위키 + Markdown 완벽 지원 · SQLite · PHP 8.2 · 소개 · 문법 안내