Bird-lg-go has a Fatal Out-of-Memory (OOM) Denial of Service via Unbounded JSON Decoding
Description
Summary
The apiHandler (and similarly webHandlerTelegramBot) processes user-provided JSON payloads by directly using json.NewDecoder(r.Body).Decode(&request) without restricting the maximum read size. An unauthenticated remote attacker can stream an extremely large, endless JSON payload (e.g., several Gigabytes of padding) over a single TCP connection. Because Go's JSON decoder attempts to allocate memory for the entire parsed structure, this rapidly exhausts the host's physical RAM or container limits, leading to an unrecoverable fatal error: runtime: out of memory.
This causes the Linux OOM Killer to instantly terminate the entire bird-lg-go daemon, resulting in a severe Remote Denial of Service (RDoS).
Details
In api.go: ```go func apiHandler(w http.ResponseWriter, r *http.Request) { var request apiRequest // VULNERABILITY: No http.MaxBytesReader protection before JSON decode err := json.NewDecoder(r.Body).Decode(&request) // ...
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/xddxdd/bird-lg-goGo | < 0.0.0-20260507060110-0ff87024cb9e | 0.0.0-20260507060110-0ff87024cb9e |
Affected products
1- Range: < 0.0.0-20260507060110-0ff87024cb9e
Patches
10ff87024cb9efrontend: limit max POST payload size in APIs
4 files changed · +56 −1
frontend/api.go+7 −0 modified@@ -6,6 +6,8 @@ import ( "net/http" ) +const maxRequestBodySize = 100 * 1024 // 100KB + type apiRequest struct { Servers []string `json:"servers"` Type string `json:"type"` @@ -107,10 +109,15 @@ func apiErrorHandler(err error) apiResponse { } func apiHandler(w http.ResponseWriter, r *http.Request) { + r.Body = http.MaxBytesReader(w, r.Body, maxRequestBodySize) var request apiRequest var response apiResponse err := json.NewDecoder(r.Body).Decode(&request) if err != nil { + if err.Error() == "http: request body too large" { + http.Error(w, "Request body too large", http.StatusRequestEntityTooLarge) + return + } response = apiResponse{ Error: err.Error(), }
frontend/api_test.go+21 −0 modified@@ -184,6 +184,27 @@ func TestApiHandlerBadJSON(t *testing.T) { assert.Equal(t, len(response.Result), 0) } +func TestApiHandlerRequestBodyTooLarge(t *testing.T) { + setting.servers = []string{"alpha"} + + largePayload := strings.Repeat("x", 1024*1024) + request := apiRequest{ + Servers: setting.servers, + Type: "server_list", + Args: largePayload, + } + requestJson, err := json.Marshal(request) + if err != nil { + t.Error(err) + } + + r := httptest.NewRequest(http.MethodPost, "/api", bytes.NewReader(requestJson)) + w := httptest.NewRecorder() + apiHandler(w, r) + + assert.Equal(t, w.Code, http.StatusRequestEntityTooLarge) +} + func TestApiHandlerInvalidType(t *testing.T) { setting.servers = []string{"alpha", "beta", "gamma"}
frontend/telegram_bot.go+5 −1 modified@@ -55,11 +55,15 @@ func telegramBatchRequestFormat(servers []string, endpoint string, command strin } func webHandlerTelegramBot(w http.ResponseWriter, r *http.Request) { - // Parse only needed fields of incoming JSON body + r.Body = http.MaxBytesReader(w, r.Body, maxRequestBodySize) var err error var request tgWebhookRequest err = json.NewDecoder(r.Body).Decode(&request) if err != nil { + if err.Error() == "http: request body too large" { + http.Error(w, "Request body too large", http.StatusRequestEntityTooLarge) + return + } println(err.Error()) return }
frontend/telegram_bot_test.go+23 −0 modified@@ -365,3 +365,26 @@ func TestWebHandlerTelegramBotTruncateLongResponse(t *testing.T) { response := mockTelegramCall(t, "/whois AS6939", false) assert.Equal(t, response, "```\n"+strings.Repeat("A", 4096)+"\n```") } + +func TestWebHandlerTelegramBotRequestBodyTooLarge(t *testing.T) { + largePayload := strings.Repeat("x", 1024*1024) + request := tgWebhookRequest{ + Message: tgMessage{ + MessageID: 123, + Chat: tgChat{ + ID: 456, + }, + Text: "/trace " + largePayload, + }, + } + requestJson, err := json.Marshal(request) + if err != nil { + t.Fatal(err) + } + + r := httptest.NewRequest(http.MethodPost, "/telegram/", bytes.NewReader(requestJson)) + w := httptest.NewRecorder() + webHandlerTelegramBot(w, r) + + assert.Equal(t, w.Code, http.StatusRequestEntityTooLarge) +}
Vulnerability mechanics
AI mechanics synthesis has not run for this CVE yet.
References
4News mentions
0No linked articles in our index yet.