From 141c95697a8aaaaa3d8974cb6bb17df2f52f1165 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Tue, 5 Aug 2025 10:09:19 -0700 Subject: [PATCH] Validate max requestable IO.read size (#53063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53063 Update `IO.read` CDP method handler to validate the received `size` parameter. This now accepts a max value of 10MB — adding a layer of safety in front of our current Android implementation, which fails at around ~15MB due to OkHttp limits. Changelog: [Internal] Reviewed By: vzaidman Differential Revision: D79646155 fbshipit-source-id: c777802105dc31cdcc7e9e960c880e689540fddd --- .../jsinspector-modern/NetworkIOAgent.cpp | 11 +++++++++- .../tests/HostTargetTest.cpp | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp b/packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp index 1449de08d07..722578f5514 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp @@ -22,6 +22,7 @@ namespace facebook::react::jsinspector_modern { static constexpr long DEFAULT_BYTES_PER_READ = 1048576; // 1MB (Chrome v112 default) +static constexpr unsigned long MAX_BYTES_PER_READ = 10485760; // 10MB // https://github.com/chromium/chromium/blob/128.0.6593.1/content/browser/devtools/devtools_io_context.cc#L71-L73 static constexpr std::array kTextMIMETypePrefixes{ @@ -403,9 +404,17 @@ void NetworkIOAgent::handleIoRead(const cdp::PreparsedRequest& req) { "Invalid params: handle is missing or not a string.")); return; } - std::optional size = std::nullopt; + std::optional size = std::nullopt; if ((req.params.count("size") != 0u) && req.params.at("size").isInt()) { size = req.params.at("size").asInt(); + + if (size > MAX_BYTES_PER_READ) { + frontendChannel_(cdp::jsonError( + requestId, + cdp::ErrorCode::InvalidParams, + "Invalid params: size cannot be greater than 10MB.")); + return; + } } auto streamId = req.params.at("handle").asString(); diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp b/packages/react-native/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp index b9956dc04ca..82bc955762f 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp @@ -1501,4 +1501,26 @@ TEST_F(HostTargetTest, NetworkLoadNetworkResource3xx) { }); } +TEST_F(HostTargetTest, IOReadSizeValidation) { + connect(); + + InSequence s; + + EXPECT_CALL(fromPage(), onMessage(JsonEq(R"({ + "id": 1, + "error": { + "message": "Invalid params: size cannot be greater than 10MB.", + "code": -32602 + } + })"))); + toPage_->sendMessage(R"({ + "id": 1, + "method": "IO.read", + "params": { + "handle": "0", + "size": 134217728 + } + })"); +} + } // namespace facebook::react::jsinspector_modern