VYPR
High severityGHSA Advisory· Published May 11, 2026· Updated May 11, 2026

Bird-lg-go has a Fatal Out-of-Memory (OOM) Denial of Service via Unbounded JSON Decoding

CVE-2026-45047

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.

PackageAffected versionsPatched versions
github.com/xddxdd/bird-lg-goGo
< 0.0.0-20260507060110-0ff87024cb9e0.0.0-20260507060110-0ff87024cb9e

Affected products

1

Patches

1
0ff87024cb9e

frontend: limit max POST payload size in APIs

https://github.com/xddxdd/bird-lg-goLan TianMay 7, 2026via ghsa
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

4

News mentions

0

No linked articles in our index yet.