Null Pointer Dereference by Crafted Response from AI Model

Disclosed: 2025-03-26 02:02:48 By canalun To brave
Low
Vulnerability Details
> NOTE! Thanks for submitting a report! Please fill all sections below with the pertinent details. Remember, the more detail you provide, the easier it is for us to verify and then potentially issue a bounty. ## Summary: - This is regarding Leo AI's "Bring your own model" feature. - An attacker has to make user set a malicious endpoint as AI's "Server endpoint". - The code handling a server response assumes a specific structure without validating it. As a result, null pointer dereference causes by a crafted response. ## Products affected: Brave browser: Version 1.74.50 Chromium: 132.0.6834.111 (Official Build) (arm64) (fyi: OS: macOS sequoia 15.2) ## Steps To Reproduce: - Open `brave://settings/leo-assistant`. - In "Bring your own model", add a model with the below params. - Label: `test` - Model request name: `test` - Server endpoint: `https://canalun.company/57e23a24db994321970941049b05d1bb` - Context size: `4000` (default) - API Key: `AAAAAAAAAAAAAAAAAAAAAA` (anything is ok) - System Prompt: `` (empty. default) - On any web page, open Leo AI sidebar, choose this model, and push the `Suggest quetions...` button. - Even if you open several tabs, the entire browser crash. ## Supporting Material/References: Log when reproducing it on local build. ``` Received signal 11 SEGV_ACCERR 000000000017 0 libbase.dylib 0x0000000105a14de4 base::debug::CollectStackTrace(base::span<void const*, 18446744073709551615ul, void const**>) + 28 1 libbase.dylib 0x00000001059fbb84 base::debug::StackTrace::StackTrace(unsigned long) + 108 2 libbase.dylib 0x0000000105a14cc0 base::debug::(anonymous namespace)::StackDumpSignalHandler(int, __siginfo*, void*) + 940 3 libsystem_platform.dylib 0x0000000190346e04 _sigtramp + 56 4 libchrome_dll.dylib 0x00000001138251ec ai_chat::OAIAPIClient::OnQueryCompleted(base::OnceCallback<void (base::expected<std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>, ai_chat::mojom::APIError>)>, api_request_helper::APIRequestResult) + 188 5 libchrome_dll.dylib 0x000000011200e4e0 void base::internal::DecayedFunctorTraits<void (brave_vpn::BraveVpnAPIRequest::*)(base::OnceCallback<void (std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, bool)>, api_request_helper::APIRequestResult), base::WeakPtr<brave_vpn::BraveVpnAPIRequest>&&, base::OnceCallback<void (std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, bool)>&&>::Invoke<void (brave_vpn::BraveVpnAPIRequest::*)(base::OnceCallback<void (std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, bool)>, api_request_helper::APIRequestResult), base::WeakPtr<brave_vpn::BraveVpnAPIRequest> const&, base::OnceCallback<void (std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, bool)>, api_request_helper::APIRequestResult>(void (brave_vpn::BraveVpnAPIRequest::*)(base::OnceCallback<void (std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, bool)>, api_request_helper::APIRequestResult), base::WeakPtr<brave_vpn::BraveVpnAPIRequest> const&, base::OnceCallback<void (std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, bool)>&&, api_request_helper::APIRequestResult&&) + 116 6 libchrome_dll.dylib 0x0000000110e0d99c base::OnceCallback<void (web_app::(anonymous namespace)::LoadedConfigs)>::Run(web_app::(anonymous namespace)::LoadedConfigs) && + 76 7 libchrome_dll.dylib 0x000000011388c4c4 api_request_helper::APIRequestHelper::DeleteAndSendResult(std::__Cr::__list_iterator<std::__Cr::unique_ptr<api_request_helper::APIRequestHelper::URLLoaderHandler, std::__Cr::default_delete<api_request_helper::APIRequestHelper::URLLoaderHandler>>, void*>, base::OnceCallback<void (api_request_helper::APIRequestResult)>, api_request_helper::APIRequestResult) + 196 8 libchrome_dll.dylib 0x000000011388e35c void base::internal::DecayedFunctorTraits<void (api_request_helper::APIRequestHelper::*)(std::__Cr::__list_iterator<std::__Cr::unique_ptr<api_request_helper::APIRequestHelper::URLLoaderHandler, std::__Cr::default_delete<api_request_helper::APIRequestHelper::URLLoaderHandler>>, void*>, base::OnceCallback<void (api_request_helper::APIRequestResult)>, api_request_helper::APIRequestResult), base::WeakPtr<api_request_helper::APIRequestHelper>&&, std::__Cr::__list_iterator<std::__Cr::unique_ptr<api_request_helper::APIRequestHelper::URLLoaderHandler, std::__Cr::default_delete<api_request_helper::APIRequestHelper::URLLoaderHandler>>, void*>&&, base::OnceCallback<void (api_request_helper::APIRequestResult)>&&>::Invoke<void (api_request_helper::APIRequestHelper::*)(std::__Cr::__list_iterator<std::__Cr::unique_ptr<api_request_helper::APIRequestHelper::URLLoaderHandler, std::__Cr::default_delete<api_request_helper::APIRequestHelper::URLLoaderHandler>>, void*>, base::OnceCallback<void (api_request_helper::APIRequestResult)>, api_request_helper::APIRequestResult), base::WeakPtr<api_request_helper::APIRequestHelper> const&, std::__Cr::__list_iterator<std::__Cr::unique_ptr<api_request_helper::APIRequestHelper::URLLoaderHandler, std::__Cr::default_delete<api_request_helper::APIRequestHelper::URLLoaderHandler>>, void*>, base::OnceCallback<void (api_request_helper::APIRequestResult)>, api_request_helper::APIRequestResult>(void (api_request_helper::APIRequestHelper::*)(std::__Cr::__list_iterator<std::__Cr::unique_ptr<api_request_helper::APIRequestHelper::URLLoaderHandler, std::__Cr::default_delete<api_request_helper::APIRequestHelper::URLLoaderHandler>>, void*>, base::OnceCallback<void (api_request_helper::APIRequestResult)>, api_request_helper::APIRequestResult), base::WeakPtr<api_request_helper::APIRequestHelper> const&, std::__Cr::__list_iterator<std::__Cr::unique_ptr<api_request_helper::APIRequestHelper::URLLoaderHandler, std::__Cr::default_delete<api_request_helper::APIRequestHelper::URLLoaderHandler>>, void*>&&, base::OnceCallback<void (api_request_helper::APIRequestResult)>&&, api_request_helper::APIRequestResult&&) + 196 9 libchrome_dll.dylib 0x0000000110e0d99c base::OnceCallback<void (web_app::(anonymous namespace)::LoadedConfigs)>::Run(web_app::(anonymous namespace)::LoadedConfigs) && + 76 10 libchrome_dll.dylib 0x000000011388e0a0 api_request_helper::APIRequestHelper::URLLoaderHandler::OnParseJsonResponse(api_request_helper::APIRequestResult, base::expected<base::Value, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>>) + 1016 11 libchrome_dll.dylib 0x000000011388ea2c void base::internal::DecayedFunctorTraits<void (api_request_helper::APIRequestHelper::URLLoaderHandler::*)(api_request_helper::APIRequestResult, base::expected<base::Value, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>>), base::WeakPtr<api_request_helper::APIRequestHelper::URLLoaderHandler>&&, api_request_helper::APIRequestResult&&>::Invoke<void (api_request_helper::APIRequestHelper::URLLoaderHandler::*)(api_request_helper::APIRequestResult, base::expected<base::Value, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>>), base::WeakPtr<api_request_helper::APIRequestHelper::URLLoaderHandler> const&, api_request_helper::APIRequestResult, base::expected<base::Value, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>>>(void (api_request_helper::APIRequestHelper::URLLoaderHandler::*)(api_request_helper::APIRequestResult, base::expected<base::Value, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>>), base::WeakPtr<api_request_helper::APIRequestHelper::URLLoaderHandler> const&, api_request_helper::APIRequestResult&&, base::expected<base::Value, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>>&&) + 184 12 libchrome_dll.dylib 0x0000000110e0d99c base::OnceCallback<void (web_app::(anonymous namespace)::LoadedConfigs)>::Run(web_app::(anonymous namespace)::LoadedConfigs) && + 76 13 libchrome_dll.dylib 0x000000011388e818 _ZN4base8internal7InvokerINS0_13FunctorTraitsIOZN18api_request_helper12_GLOBAL__N_127ParseJsonInWorkerTaskRunnerENSt4__Cr12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEPNS_19SequencedTaskRunnerENS_12OnceCallbackIFvNS_8expectedINS_5ValueESB_EEEEEE3$_1JOSJ_EEENS0_9BindStateILb0ELb0ELb0ESK_JSJ_EEEFvNSF_ISG_NS_10JSONReader5ErrorEEEEE7RunOnceEPNS0_13BindStateBaseEOSS_ + 92 14 libchrome_dll.dylib 0x0000000110e0d99c base::OnceCallback<void (web_app::(anonymous namespace)::LoadedConfigs)>::Run(web_app::(anonymous namespace)::LoadedConfigs) && + 76 15 libchrome_dll.dylib 0x0000000110ffb9ac void base::internal::ReplyAdapter<base::expected<base::Value, base::JSONReader::Error>, base::expected<base::Value, base::JSONReader::Error>>(base::OnceCallback<void (base::expected<base::Value, base::JSONReader::Error>)>, std::__Cr::unique_ptr<base::expected<base::Value, base::JSONReader::Error>, std::__Cr::default_delete<base::expected<base::Value, base::JSONReader::Error>>>*) + 56 16 libchrome_dll.dylib 0x0000000110e9a904 base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(base::OnceCallback<web_app::(anonymous namespace)::LoadedConfigs ()>, std::__Cr::unique_ptr<web_app::(anonymous namespace)::LoadedConfigs, std::__Cr::default_delete<web_app::(anonymous namespace)::LoadedConfigs>>*), base::OnceCallback<web_app::(anonymous namespace)::LoadedConfigs ()>&&, std::__Cr::unique_ptr<web_app::(anonymous namespace)::LoadedConfigs, std::__Cr::default_delete<web_app::(anonymous namespace)::LoadedConfigs>>*&&>, base::internal::BindState<false, true, false, void (*)(base::OnceCallback<web_app::(anonymous namespace)::LoadedConfigs ()>, std::__Cr::unique_ptr<web_app::(anonymous namespace)::LoadedConfigs, std::__Cr::default_delete<web_app::(anonymous namespace)::LoadedConfigs>>*), base::OnceCallback<web_app::(anonymous namespace)::LoadedConfigs ()>, base::internal::UnretainedWrapper<std::__Cr::unique_ptr<web_app::(anonymous namespace)::LoadedConfigs, std::__Cr::default_delete<web_app::(anonymous namespace)::LoadedConfigs>>, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void ()>::RunOnce(base::internal::BindStateBase*) + 36 17 libbase.dylib 0x00000001058e2194 base::OnceCallback<void ()>::Run() && + 68 18 libbase.dylib 0x00000001059b5624 base::internal::PostTaskAndReplyRelay::RunReply(base::internal::PostTaskAndReplyRelay) + 44 19 libbase.dylib 0x00000001059b5500 base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(base::internal::PostTaskAndReplyRelay), base::internal::PostTaskAndReplyRelay&&>, base::internal::BindState<false, true, false, void (*)(base::internal::PostTaskAndReplyRelay), base::internal::PostTaskAndReplyRelay>, void ()>::RunOnce(base::internal::BindStateBase*) + 44 20 libbase.dylib 0x00000001058e2194 base::OnceCallback<void ()>::Run() && + 68 21 libbase.dylib 0x000000010597c91c base::TaskAnnotator::RunTaskImpl(base::PendingTask&) + 280 22 libbase.dylib 0x00000001059aa8b8 base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*) + 1020 23 libbase.dylib 0x00000001059aa158 base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() + 100 24 libbase.dylib 0x0000000105a278d0 base::MessagePumpCFRunLoopBase::RunWork() + 156 25 libbase.dylib 0x0000000105a1e6e8 base::apple::CallWithEHFrame(void () block_pointer) + 16 26 libbase.dylib 0x0000000105a26e28 base::MessagePumpCFRunLoopBase::RunWorkSource(void*) + 68 27 CoreFoundation 0x00000001903f8894 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28 28 CoreFoundation 0x00000001903f8828 __CFRunLoopDoSource0 + 176 29 CoreFoundation 0x00000001903f858c __CFRunLoopDoSources0 + 244 30 CoreFoundation 0x00000001903f7128 __CFRunLoopRun + 840 31 CoreFoundation 0x00000001903f6724 CFRunLoopRunSpecific + 588 32 HIToolbox 0x000000019b94e530 RunCurrentEventLoopInMode + 292 33 HIToolbox 0x000000019b954348 ReceiveNextEventCommon + 676 34 HIToolbox 0x000000019b954508 _BlockUntilNextEventMatchingListInModeWithFilter + 76 35 AppKit 0x0000000193f61034 _DPSNextEvent + 660 36 AppKit 0x00000001948c52d4 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688 37 libchrome_dll.dylib 0x0000000112609ac8 __71-[BrowserCrApplication nextEventMatchingMask:untilDate:inMode:dequeue:]_block_invoke + 64 38 libbase.dylib 0x0000000105a1e6e8 base::apple::CallWithEHFrame(void () block_pointer) + 16 39 libchrome_dll.dylib 0x0000000112609a10 -[BrowserCrApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 188 40 AppKit 0x0000000193f54060 -[NSApplication run] + 480 41 libbase.dylib 0x0000000105a28588 base::MessagePumpNSApplication::DoRun(base::MessagePump::Delegate*) + 396 42 libbase.dylib 0x0000000105a26794 base::MessagePumpCFRunLoopBase::Run(base::MessagePump::Delegate*) + 140 43 libbase.dylib 0x00000001059ab4e8 base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta) + 528 44 libbase.dylib 0x00000001059504c0 base::RunLoop::Run(base::Location const&) + 360 45 libcontent.dylib 0x000000012090237c content::BrowserMainLoop::RunMainMessageLoop() + 180 46 libcontent.dylib 0x0000000120903fb8 content::BrowserMainRunnerImpl::Run() + 48 47 libcontent.dylib 0x00000001208ff968 content::BrowserMain(content::MainFunctionParams) + 152 48 libcontent.dylib 0x00000001216089dc content::RunBrowserProcessMain(content::MainFunctionParams, content::ContentMainDelegate*) + 176 49 libcontent.dylib 0x000000012160a028 content::ContentMainRunnerImpl::RunBrowser(content::MainFunctionParams, bool) + 1020 50 libcontent.dylib 0x0000000121609b14 content::ContentMainRunnerImpl::Run() + 548 51 libcontent.dylib 0x0000000121608048 content::RunContentProcess(content::ContentMainParams, content::ContentMainRunner*) + 1244 52 libcontent.dylib 0x0000000121608284 content::ContentMain(content::ContentMainParams) + 112 53 libchrome_dll.dylib 0x0000000110e06dac ChromeMain + 684 54 Brave Browser Development 0x0000000104f007e0 main + 288 55 dyld 0x000000018ff90274 start + 2840 [end of stack trace] [0125/231828.615759:ERROR:bootstrap.cc(65)] bootstrap_look_up com.apple.ReportCrash: Unknown service name (1102) [1] 67722 segmentation fault --enable-logging --v=0 --disable-brave-update --use-mock-keychain ``` This is caused by here. ``` void OAIAPIClient::OnQueryCompleted(GenerationCompletedCallback callback, APIRequestResult result) { const bool success = result.Is2XXResponseCode(); // Handle successful request if (success) { std::string completion = ""; // We're checking for a value body in case for non-streaming API results. if (result.value_body().is_dict()) { const base::Value::List* choices = result.value_body().GetDict().FindList("choices"); if (!choices) { DVLOG(2) << "No choices list found in response."; return; } if (choices->front().is_dict()) { const base::Value::Dict* message = choices->front().GetDict().FindDict("message"); if (!message) { DVLOG(2) << "No message dict found in response."; return; } completion = *message->FindString("content"); // ***HERE*** The code assumes the `message` field always has at least one `content` field. } } std::move(callback).Run(base::ok(std::move(completion))); return; } // omit // } ``` I think nullptr check should be added. ## Impact - It always causes a crash of the entire browser. - In general, null pointer dereferences leads to RCE in some cases. - I've not been occurred by any idea to exploit this for RCE. - I know just a crash is not rewarded, but reported the issue just in case, because it could be used as a step stone to RCE and especially it's in the privileged browser process.
Actions
View on HackerOne
Report Stats
  • Report ID: 2958097
  • State: Closed
  • Substate: resolved
Share this report