Skip to content

Invalid JSON desearilaztion beyond buffer end #183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
5 tasks done
ayavilevich opened this issue May 23, 2025 · 2 comments · May be fixed by #184
Open
5 tasks done

Invalid JSON desearilaztion beyond buffer end #183

ayavilevich opened this issue May 23, 2025 · 2 comments · May be fixed by #184
Assignees
Labels
Type: Bug Something isn't working

Comments

@ayavilevich
Copy link

Platform

ESP32

IDE / Tooling

PlatformIO

What happened?

When calling the JSON handler with a scalar (number) the parsing fails and the handler returns a "HTTP/1.1 400 Bad Request" response instead of parsing the JSON correctly.

The curl command: curl -v -X POST -H 'Content-Type: application/json' -d '5' http://192.168.4.1/json2

Cause
AsyncCallbackJsonWebHandler class in AsyncJson.cpp will deserialize the body by using deserializeJson function of ArduinoJson. That function expects a null terminated string or the length of the data in the buffer as a third parameter. Instead, the caller passes a non null terminated buffer without a length parameter.

Reference
Proposed fix has been described here: me-no-dev#807
P.S. I will attempt a PR for the fix.
Discussion here: #182

With the fix described above, the issue is resolved.

Worth to note that there could be other unexpected behavior to this issue, including security issues, depending on the content that follows the buffer. This is however a re-producible case.

Stack Trace

curl result:

curl -v -X POST -H "Content-Type: application/json" -d "5" http://192.168.4.1/json2
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying xxx
* Connected to xxx port 80
> POST /json2 HTTP/1.1
> Host: xxxx
> User-Agent: curl/8.9.1
> Accept: */*
> Content-Type: application/json
> Content-Length: 1
>
* upload completely sent off: 1 bytes
< HTTP/1.1 400 Bad Request
< connection: close
< accept-ranges: none
< content-length: 0
<
* shutting down connection #

Nothing appears in ESP32 serial output because the handler blocks the response from getting to the main code.


With the fix described in original issue 807 applied:

curl result:

C:\Users\arik>curl -v -X POST -H "Content-Type: application/json" -d "5" http://192.168.4.1/json2
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying xxxxx
* Connected to xxxx port 80
> POST /json2 HTTP/1.1
> Host: xxxx
> User-Agent: curl/8.9.1
> Accept: */*
> Content-Type: application/json
> Content-Length: 1
>
* upload completely sent off: 1 bytes
< HTTP/1.1 200 OK
< connection: close
< accept-ranges: none
< content-length: 3
< content-type: text/plain
<
int* shutting down connection #0

ESP32 serial

12:01:59.418 > . Json:
12:04:39.267 > 5
12:04:39.267 > Got an int

Minimal Reproductible Example (MRE)

// based on https://github.com/ESP32Async/ESPAsyncWebServer/blob/main/examples/Json/Json.ino
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov

#include <Arduino.h>
#include <AsyncTCP.h>
#include <WiFi.h>

#include <ESPAsyncWebServer.h>

#include <ArduinoJson.h>
#include <AsyncJson.h>
#include <AsyncMessagePack.h>

static AsyncWebServer server(80);

static AsyncCallbackJsonWebHandler *handler = new AsyncCallbackJsonWebHandler("/json2");

void setup()
{
  Serial.begin(115200);

  // setup wifi
  // AP
  // WiFi.mode(WIFI_AP);
  // WiFi.softAP("esp-captive");
  // client
  WiFi.mode(WIFI_STA); // for STA mode
  WiFi.begin("x", "y");
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(". ");
    delay(500);
  }

  // test cases
  // curl -v -X POST -H 'Content-Type: application/json' -d '{' http://192.168.4.1/json2
  // curl -v -X POST -H 'Content-Type: application/json' -d '5' http://192.168.4.1/json2
  handler->setMethod(HTTP_POST);
  handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json)
                     {
    Serial.println("Json:");
    serializeJson(json, Serial);
    Serial.println();
    if(json.is<int>())
    {
      Serial.println("Got an int");
    }
    // response
    request->send(200, "text/plain", json.is<int>() ? "int" : "not int"); });

  server.addHandler(handler);

  server.begin();
}

// not needed
void loop()
{
  delay(100);
}

I confirm that:

  • I have read the documentation.
  • I have searched for similar discussions.
  • I have searched for similar issues.
  • I have looked at the examples.
  • I have upgraded to the lasted version of ESPAsyncWebServer (and AsyncTCP for ESP32).
ayavilevich added a commit to ayavilevich/ESPAsyncWebServer that referenced this issue May 23, 2025
@ayavilevich ayavilevich linked a pull request May 23, 2025 that will close this issue
@mathieucarbou mathieucarbou added Type: Bug Something isn't working and removed Status: Awaiting triage labels May 23, 2025
@mathieucarbou
Copy link
Member

Nothing appears in ESP32 serial output because the handler blocks the response from getting to the main code.

That's what would probably need to be fixed ?

@ayavilevich
Copy link
Author

That's what would probably need to be fixed ?

Sure. Once it tries to parse the right input size then the parsing will succeed and it will pass the JSON object to the onRequest handler.

@mathieucarbou mathieucarbou linked a pull request May 24, 2025 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants