메뉴
HN
Hacker News 23일 전

클로드로 파이어폭스 보안 강화하기

IMP
9/10
핵심 요약

Claude와 같은 AI 모델을 활용해 파이어폭스 내 상당수의 숨겨진 보안 취약점을 발견하고 수정한 사례를 공유했습니다. 과거 쓰레기에 불과했던 AI 생성 버그 리포트의 퀄리티는 모델 고도화 및 활용 기술 개선을 통해 매우 정교한 수준으로 발전했습니다. 이 과정에서 샌드박스 탈출, 20년 된 메모리 누수 등 치명적인 취약점들이 다수 발견되었으며, 이는 소프트웨어 방어자들에게 AI를 적극 도입해야 하는 이유를 시사합니다.

번역된 본문

두 주 전, 저희는 Claude Mythos Preview 및 다른 AI 모델들의 도움을 받아 파이어폭스에서 전례 없는 수의 숨겨진 보안 버그를 식별하고 수정했다고 발표했습니다. 이 글에서는 저희가 이 작업에 어떻게 접근했는지, 무엇을 발견했는지, 그리고 다른 프로젝트들이 새롭게 떠오르는 AI 기능을 잘 활용해 공격으로부터 스스로를 방어할 수 있는 조언을 더 자세히 다룰 것입니다.

갑자기 버그 리포트가 매우 훌륭해졌습니다. 불과 몇 달 전만 해도 오픈 소스 프로젝트에 제출되는 AI 생성 보안 버그 리포트는 대부분 원치 않는 쓰레기로 통했습니다. 그럴듯해 보이지만 틀린 보고서를 다루는 것은 프로젝트 유지 관리자에게 비대칭적인 비용을 부과합니다. 코드에서 '문제점'을 찾기 위해 대형 언어 모델(LLM)에 프롬프트를 입력하는 것은 싸고 쉽지만, 그에 응답하는 것은 느리고 비용이 많이 듭니다.

이러한 역학이 단 몇 달 만에 우리에게 얼마나 크게 변화했는지 아무리 강조해도 지나치지 않습니다. 이는 주로 두 가지 주요 요인의 결합 덕분이었습니다. 첫째, 모델의 성능이 크게 향상되었습니다. 둘째, 이러한 모델들을 활용하는 우리의 기술, 즉 모델을 조종하고(sterring), 확장하며(scaling), 쌓아올려(stacking) 대량의 유효한 정보를 생성하고 노이즈를 필터링하는 기술이 극적으로 개선되었습니다.

일반적으로 저희는 수정 사항을 배포하고 보안 권고문을 발행한 후에도 몇 달 동안 자세한 버그 보고서를 비공개로 유지합니다. 이는 주로 어떤 이유로든 최신 버전의 파이어폭스로 업데이트하는 데 느린 사용자를 보호하기 위한 예방 조치입니다. 하지만 이 주제에 대한 비범한 관심 수준과 소프트웨어 생태계 전반에 즉각적인 행동이 필요하다는 절박함을 고려하여, 저희는 최근 배포한 수정 사항의 배경이 되는 보고서 중 작은 샘플을 공개하기로 계산된 결정을 내렸습니다. 브라우저의 다양한 하위 시스템에서 이들을 추출하려고 노력했지만, 선택 과정은 여전히 다소 자의적이었습니다. 그럼에도 불구하고 이 보고서들의 깊이와 다양성이 저희의 AI 역능 평가와 방어자들에게 이러한 기술을 적용할 것을 촉구하는 호소에 신빙성을 더해주기를 바랍니다:

  • Bug ID 2024918: 잘못된 동등성(equality) 검사로 인해 JIT(JIT)가 라이브 WebAssembly GC 구조체의 초기화를 최적화 과정에서 생략할 수 있습니다. 이로 인해 내부 및 외부 연구원들의 광범위한 퍼징(fuzzing)을 거친 코드에서 임의 읽기/쓰기가 가능한 가짜 객체(fake-object) 프리미티브가 생성됩니다.
  • Bug ID 2024437: 재귀 스택 깊이 제한, expando 속성, 주기 수집(cycle collection) 등 브라우저의 멀리 떨어진 부분에 걸친 엣지 케이스의 세밀한 조율로 인해 트리거되는 <legend> 요소의 15년 된 버그입니다.
  • Bug ID 2021894: IPC를 통한 경쟁 상태(Race condition)를 안정적으로 악용하여, 손상된 콘텐츠 프로세스가 상위 프로세스의 IndexedDB 참조 횟수(refcount)를 조작해 UAF(Use-After-Free)를 유발하고 잠재적인 샌드박스 탈출(sandbox escape)을 트리거할 수 있습니다.
  • Bug ID 2022034: IPC 경계를 넘나드는 원시 NaN 값이 태그된 JS 객체 포인터로 위장할 수 있으며, 이로 인해 역직렬화가 두 번 발생해 상위 프로세스에서 샌드박스 탈출을 위한 가짜 객체 프리미티브가 됩니다.
  • Bug ID 2024653: 중첩된 이벤트 루프, pagehide 리스너 및 가비지 컬렉션을 관통하는 복잡한 테스트 케이스를 통해 <object> 요소의 속성 설정자(setter)에서 UAF를 트리거합니다.
  • Bug ID 2022733: 수천 개의 인증서 해시를 WebTransport로 flooding하여 참조 횟수가 많은 복사 루프의 경쟁 상태를 늘린 뒤, 손상된 콘텐츠 프로세스에서 IPC를 통해 이 경쟁 상태를 악용해 상위 프로세스의 UAF를 트리거합니다.
  • Bug ID 2023958: glibc DNS 함수 호출을 가로채어 악의적인 DNS 서버를 시뮬레이션함으로써 UDP에서 TCP로의 대체(fallback) 엣지 케이스를 재현합니다. 이 과정에서 HTTPS RR 및 ECH 구문 분석 중 버퍼 과다 읽기(over-read) 및 상위 프로세스의 스택 메모리 누수가 발생합니다.
  • Bug ID 2025977: 재진입하는 key() 호출이 해시 테이블의 리해시를 유발하여, 원시 엔트리 포인터가 여전히 사용 중일 때 백업 저장소를 해제하는 20년 된 XSLT 버그입니다. (해당 문제는 XSLT와 관련하여 저희가 수정한 여러 sec-high 문제 중 하나입니다).
  • Bug ID 2027298: 색상 선택기에 패치를 적용해 자동화할 수 없는 사용자 선택을 시뮬레이션한 다음, 동기 입력 이벤트를 사용하여 중첩된 이벤트 루프를 돌립니다. 이 루프는 액터 해체(teardown)에 다시 진입해 콜백이 여전히 unwinding 중일 때 이를 해제하여 콘텐츠 프로세스의 UAF를 트리거합니다.
  • Bug ID 2023817: 손상된 콘텐츠 프로세스가 임의의 배경 화면 이미지를 보낼 수 있는 문제입니다.
원문 보기
원문 보기 (영어)
Two weeks ago we announced that we had identified and fixed an unprecedented number of latent security bugs in Firefox with the help of Claude Mythos Preview and other AI models. In this post, we’ll go into more detail about how we approached this work, what we found, and advice for other projects on making good use of emerging capabilities to harden themselves against attack. Suddenly, the bugs are very good Just a few months ago, AI-generated security bug reports to open source projects were mostly known for being unwanted slop. Dealing with reports that look plausibly correct but are wrong imposes an asymmetric cost on project maintainers: it’s cheap and easy to prompt an LLM to find a “problem” in code, but slow and expensive to respond to it. It is difficult to overstate how much this dynamic changed for us over a few short months. This was due to a combination of two main factors. First, the models got a lot more capable. Second, we dramatically improved our techniques for harnessing these models — steering them, scaling them, and stacking them to generate large amounts of signal and filter out the noise. Ordinarily we keep detailed bug reports private for several months after shipping fixes and issuing security advisories, largely as a precaution to protect any users who, for whatever reason, were slow to update to the latest version of Firefox. Given the extraordinary level of interest in this topic and the urgency of action needed throughout the software ecosystem, we’ve made the calculated decision to unhide a small sample of the reports behind the fixes we recently shipped. We’ve attempted to draw them from a range of browser subsystems, but the selection process was still somewhat arbitrary. Nevertheless, we hope that the depth and diversity of these reports lends credence to our assessment of the capabilities and our calls for defenders to begin applying these techniques: Bug ID Description 2024918 An incorrect equality check can cause the JIT to optimize away the initialization of a live WebAssembly GC struct, creating a fake-object primitive with potential arbitrary read/write in code that had undergone extensive fuzzing by internal and external researchers. 2024437 A 15-year-old bug in the <legend> element triggered by meticulous orchestration of edge cases across distant parts of the browser, including recursion stack depth limits, expando properties, and cycle collection. 2021894 Reliably exploits a race condition over IPC, allowing a compromised content process to manipulate IndexedDB refcounts in the parent to trigger a UAF and potential sandbox escape. 2022034 A raw NaN crossing an IPC boundary can masquerade as a tagged JS object pointer, turning double deserialization into a parent-process fake-object primitive for a sandbox escape. 2024653 An intricate testcase weaving through nested event loops, pagehide listeners, and garbage collection to trigger a UAF in the attribute setter for <object> elements. 2022733 Triggers a parent UAF by flooding WebTransport with thousands of certificate hashes to stretch a race condition in a refcount-heavy copy loop, and exploits that race condition over IPC from a compromised content process. 2023958 Simulates a malicious DNS server by intercepting glibc DNS function calls in order to reproduce a UDP->TCP fallback edge case, triggering a buffer over-read and parent-process stack memory leak during HTTPS RR & ECH parsing. 2025977 20-year-old XSLT bug in which reentrant key() calls cause a hash table rehash that frees its backing store while a raw entry pointer is still in use (one of several sec-high issues we fixed involving XSLT). 2027298 Patches the color picker to simulate otherwise non-automatable user selection, then uses a synchronous input event to spin a nested event loop that re-enters actor teardown and frees the callback while it is still unwinding, triggering a content process UAF. 2023817 A compromised content process could send an arbitrary wallpaper image to be decoded in the parent process, which could be paired with a hypothetical vulnerability in an image decoder to escape the sandbox. This entailed difficult-to-automate reasoning about the trust-level of inputs in the parent process. 2029813 Escapes our in-process sandboxing technology for third-party libraries ( RLBox ) by leveraging a gap in the verification logic used to copy values from the untrusted to the trusted side of the sandbox boundary. 2026305 Extremely small testcase that exploits the special rowspan=0 semantics in HTML tables by appending >65535 rows to bypass clamping and overflow a 16-bit layout bitfield, which went undetected for years by fuzzers. Note that a number of these bugs are sandbox escapes , which would need to be combined with other exploits to achieve a full-chain Firefox compromise. These reports presume that the sandboxed process that renders site content has already been compromised with some separate bug, and is now running attacker-controlled machine code attempting to escalate control into the privileged parent process. When crafting a sandbox escape, the model is permitted to patch the Firefox source code, so long as the modified code is restricted to run only in the sandboxed process [1] . Such bugs are notoriously difficult to find with fuzzing, and while we’ve had some success developing new techniques to close this gap, AI analysis provides much more comprehensive coverage of this critical surface. Just as interesting as what the models found is what they didn’t find — not because they didn’t try, but because they were unable to circumvent Firefox’s layered defenses. For example, in recent years we received several clever reports from security researchers that managed to escape the process sandbox by triggering prototype pollution in the privileged parent process. Rather than fixing these problems one-by-one, we made an architectural change to freeze these prototypes by default. While auditing logs from the harness, we saw many attempts to pursue this line of escape that were thwarted by this design. Observing such direct payoff from previous hardening work was even more rewarding than finding and fixing more bugs. Harnessing Models to Build a Hardening Pipeline We've experimented internally with LLM code audits over the past few years, with early attempts using models like GPT 4 or Sonnet 3.5 to statically analyze high risk code for vulnerabilities. These experiments showed some promise, but the high rate of false positives made them impractical to scale. The introduction of agentic harnesses that can reliably detect security issues has completely changed this. These can find real bugs and dismiss unreproducible speculation. The key feature of such a harness is that, given the right interfaces and instructions, it can create and run reproducible test cases to dynamically test hypotheses about bugs in code. After fixing the initial set of issues that Anthropic sent to us in February, we built our own harness atop our existing fuzzing infrastructure . We began with small-scale experiments prompting the harness to look for sandbox escapes with Claude Opus 4.6. Even with this model, we identified an impressive amount of previously-unknown vulnerabilities which required complex reasoning over multiprocess browser engine code. At first, we supervised the process in the terminal to observe the process in real-time and tune the prompts and logic. Once this was working well, we parallelized the jobs across multiple ephemeral VMs, each tasked to hunt for bugs within a specific target file and write its findings back to a bucket. A discovery subsystem is necessary but not sufficient. In order to scale the effort, we needed to integrate it with our full security bug lifecycle: determining what to look for, where to look, and how to handle what it produces. This last part includes deduplicating against known issues, tracking bugs, triaging them, and getting fixes shipped. While the model is the