DEEP DIVE REPORT

CVE-2026-128069: rails-html-sanitizer 동시 호출 XSS 조건과 1.7.2 업데이트 점검

SecurityDesk
• 2026.11.14 • 조회 2

rails-html-sanitizer의 허용 목록이 호출마다 다르다면, CVE-2026-128069는 버전 번호 확인보다 적용 조건 확인이 먼저인 취약점입니다. 1.7.2 이전 버전은 정제에 쓰는 객체를 호출 사이에 재사용하고 그 객체의 허용 태그와 속성을 잠금 없이 바꾸기 때문에, 스레드가 여러 개인 프로세스에서 허용 목록이 실제로 다르게 쓰인 호출이 겹치면 한 호출이 다른 호출의 규칙으로 내용을 정제할 수 있습니다.

개요

개요 인포그래픽
rails-html-sanitizer는 Rails 애플리케이션의 HTML 단편을 정제하는 라이브러리입니다. CVE Program에 등록된 CVE-2026-128069 레코드에 따르면 1.7.2 이전 버전에서는 Rails::HTML::SafeListSanitizer의 HTML4 변형과 HTML5 변형이 하나의 Rails::HTML::PermitScrubber를 호출 사이에 재사용하고, 이 스크러버의 tags와 attributes를 동기화 없이 변경합니다.

Rails 보안 공지 GHSA-h7wh-q2qr-458c는 이 상태 공유가 크로스사이트 스크립팅(XSS)으로 이어질 수 있다고 안내합니다. 한 호출이 다른 호출의 허용 목록으로 실행되면 애초에 막으려던 태그나 속성이 정제 결과에 남을 수 있고, 그렇게 남은 요소에 브라우저가 동작할 수 있는 내용이 실리면 XSS 위험이 성립합니다.

다만 이 취약점은 라이브러리를 쓰는지 여부만으로 판정되지 않습니다. 공지 자체가 영향 조건을 스레드 구성과 호출별 허용 목록의 차이로 좁혀 두고 있어, 이번 취약점의 실질은 버전 비교보다 조건 판정에 가깝습니다.

영향 범위

영향은 다음 조건이 한 애플리케이션에서 함께 성립할 때로 한정됩니다.

  • 프로세스당 하나를 넘는 스레드로 실행돼야 합니다.
  • sanitize 호출에 넘기는 tags: 또는 attributes: 허용 목록이 다른 호출과 실제로 달라야 합니다. 옵션을 넘기지 않은 호출은 기본 허용 목록을 따르므로, 기본값을 쓰는 호출과 명시적 목록을 쓰는 호출이 같은 코드베이스에 있다는 사실만으로는 조건이 충족되지 않습니다. 명시적 목록이 그 기본값과 실제로 다를 때 비로소 서로 다른 허용 목록을 쓰는 조합이 됩니다.
  • 대상 버전은 1.7.2 이전 rails-html-sanitizer의 HTML4 및 HTML5 SafeListSanitizer입니다.

반대로 모든 호출에 같은 설정을 쓰거나, 호출마다 자체 scrubber:를 전달하거나, 단일 스레드로 실행하는 애플리케이션은 공지된 조건에 해당하지 않습니다.

이 조건식은 점검의 방향을 바꿉니다. 스레드를 쓰는 Rails 앱이라도 정제 호출이 하나의 공통 허용 목록만 따른다면 이번 조건에는 걸리지 않고, 반대로 프로세스당 여러 스레드를 쓴다는 사실만으로 영향 범위가 정해지지도 않습니다. 그래서 점검은 코드와 실행 구성을 함께 봐야 합니다. 영향 대상 버전인지, 호출마다 자체 scrubber:를 전달하지는 않는지, 프로세스당 스레드 수가 몇인지, 호출 간 허용 목록이 이름만 다른 채 같은 값은 아닌지를 한 번에 봅니다. 스레드 구성과 허용 목록의 실제 차이가 한 애플리케이션에서 함께 확인되면 그 애플리케이션이 우선 검토 대상입니다.

기술적 분석

경쟁 조건은 허용 목록이 저장되는 지점에서 발생합니다. SafeListSanitizer는 호출마다 새 PermitScrubber를 만들지 않고 하나를 재사용하고, tags:와 attributes: 옵션은 그 공유 객체의 항목을 덮어씁니다. 동기화가 없는 상태에서 서로 다른 허용 목록을 쓴 호출이 겹치면, 한 호출이 다른 호출의 설정으로 정제될 수 있습니다.

재현은 이 순서를 분명히 보여줍니다. 이슈 #228에 공유된 결정적인 두 스레드 모델은 호출 A를 tags= 설정 직후에서 멈추고 호출 B를 끝까지 실행하게 합니다. 1.7.1과 그 시점의 main 브랜치에서 호출 A는 tags: ["p"], attributes: ["id"]를 요청하고도, 호출 B가 tags: ["span"], attributes: ["class"]를 사용한 뒤 결과로 "A<span>B</span>"를 받았습니다.

결과만 보면 정제기가 제 역할을 놓친 것처럼 보이지만, 재현에서 확인된 범위는 호출 B가 허용한 span 태그가 호출 A의 결과에 남았다는 점입니다. 여기서 끌어낼 수 있는 핵심은 정제 규칙이 호출 인수가 아니라 호출 사이에 공유된 가변 상태에서 결정될 수 있다는 것입니다. 다만 이 재현은 스레드 순서를 명시적으로 조정한 결정적 모델이므로, 서로 다른 허용 목록을 쓴 호출이 실제로 겹치는 타이밍이 와야 결과가 갈립니다.

수정은 공유 상태를 없애는 방향으로 들어갔습니다. Build a PermitScrubber per SafeListSanitizer call 커밋의 변경 요약은 한 문장입니다. SafeListSanitizer가 더 이상 호출 사이에 PermitScrubber를 공유하지 않습니다. 설정 쓰기를 잠금으로 직렬화하는 대신 호출마다 스크러버를 따로 쓰게 해, 경쟁이 일어날 자리 자체를 제거한 것입니다.

동시 호출에 따른 정제 결과의 변화는 위 재현 모델에서 확인됐습니다. 다만 재현 결과만으로 실제 환경에서의 악용을 단정할 수는 없습니다.

대응 방안

먼저 확인할 것

  • 실행 중인 Rails 프로세스가 스레드를 여러 개 쓰는 구성인지 확인합니다.
  • 모든 sanitize 호출을 훑어, 명시적으로 tags: 또는 attributes:를 넘기는 호출끼리 값이 다른지 먼저 봅니다. 이어서 옵션을 생략해 기본 허용 목록을 따르는 호출이 명시적 목록과 실제로 다른 값과 함께 쓰이는지 따로 확인합니다.
  • 스레드 구성과 허용 목록의 실제 차이가 한 애플리케이션에서 함께 확인되면, 그 애플리케이션을 우선 검토합니다.

업데이트 전에 검토하는 우회책

공지는 두 가지 우회책을 안내합니다. 모든 sanitize 호출에 같은 허용 목록을 사용하는 방법, 그리고 호출마다 만든 Rails::HTML::PermitScrubber.new에 tags=와 attributes=를 설정해 tags:나 attributes: 옵션 대신 scrubber:로 전달하는 방법입니다.

허용 목록을 통일하면 정제 규칙은 하나로 고정되지만, 어떤 호출이 원래 허용하려던 요소가 통일된 목록 범위에서 지워지지 않는지 확인이 필요합니다. 호출마다 스크러버를 넘기는 방법은 의도한 허용 범위를 유지하면서 공유 상태를 피할 수 있습니다. 어느 쪽이든 애플리케이션의 모든 sanitize 호출에 일관되게 적용됐는지 검증해야 하고, 우회책은 이름 그대로 수정 릴리스를 대체하지 않습니다.

1.7.2 업데이트와 Ruby 호환성

  • rails-html-sanitizer를 1.7.2로 업데이트한 뒤 애플리케이션의 정제 동작을 검증합니다. 이 릴리스의 수정은 호출 간 PermitScrubber 공유를 제거합니다.
  • 릴리스 v1.7.2는 Ruby 3.2 이상을 요구합니다. Loofah 2.25.3이 Ruby 3.2 이상을 필요로 하기 때문입니다.
  • 1.6.x와 1.5.x 릴리스 브랜치는 더 이상 보안 업데이트를 받지 않습니다. 보안 지원 대상인 Rails 릴리스는 rails-html-sanitizer 1.7을 허용하고 Ruby 3.2 이상을 요구합니다.

버전만 올리면 되는 작업으로 끝나지 않을 수 있습니다. Ruby 3.2 미만에서 실행 중이거나 1.6.x·1.5.x 계열에 남아 있는 환경이라면, 의존성 업데이트가 Ruby 또는 Rails 릴리스 검토로 이어질 수 있어 변경 영향을 미리 평가해야 합니다.

검증

서로 다른 허용 목록을 사용하는 동시 호출에서 정제 결과가 각 호출의 의도와 일치하는지 시험합니다. 우회책을 적용한 경우와 1.7.2로 업데이트한 경우 각각에서 같은 시험을 돌려, 호출 A의 결과에 호출 B의 허용 목록이 스며드는 현상이 남아 있지 않은지 확인합니다.

한계

실제 악용 사례, 신뢰할 수 있는 공격 탐지 지표, 운영 환경에서의 악용 빈도는 확인되지 않았습니다. 이 글의 조건 판정과 우선순위는 공개된 재현 모델과 공급업체 공지에 근거하며, 확인되지 않은 악용 사실을 전제하지 않습니다.

참고자료

함께 읽으면 좋은 글

본 콘텐츠는 AI 기술로 작성된 분석 리포트를 포함하고 있습니다. 내용 중 사실과 다르거나 보완이 필요한 정보를 발견하셨으면 댓글을 통해 의견을 부탁드립니다. 여러분의 피드백은 더 정확한 보안 정보 공유에 큰 도움이 됩니다.

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

로그인

아직 댓글이 없습니다.

첫 번째 댓글을 작성해보세요!

IT 도구 서랍

→ Unix: 2025-01-15T09:30:00
→ 날짜: 1736934600

→ ASCII: ABC
→ 문자: 65 66 67

ASCII 코드표 — 클릭하면 입력란에 추가

DecHex약어설명
DecHex문자
DecHex문자

→ 유니코드: 홍길동
→ 문자: \ud64d\uae38\ub3d9