Disclosure Date: 2023-10-16
Affected Project: usememos/memos
Affected Versions: Prior to .13.2
Severity: Medium

What’s CVE-2023-4698 All About?

On October 16, 2023, a vulnerability titled CVE-2023-4698 was published for the open-source note-taking app usememos/memos. This flaw is an improper input validation bug found in all versions before .13.2.

If an attacker knows how, they could submit crafted data that isn’t properly checked, leading to possible unauthorized data manipulation or a minor security issue like unintended server actions.

What Is Improper Input Validation?

Improper input validation is when a program doesn't properly check (or sanitize) user data before using it. This can open the door to different attacks, including injection, authentication bypass, or even data corruption.

In simple terms: The app trusts user data too much, and lets bad info slip through.


## What Exactly Was Wrong in usememos/memos?

The specific bug in usememos/memos appeared in an API endpoint that didn't check if the incoming data was what it was supposed to be. For example, if a field expects a number, the application didn’t complain if you sent a string, boolean, or even some code.

Here’s a possible snippet (not real, but similar in spirit)

// Example: before the fix (improper validation)
func handleMemoCreate(c *gin.Context) {
    var input Memo
    c.BindJSON(&input)         // <-- doesn't check the structure strictly enough
    db.Create(&input)
    c.JSON(200, input)
}

What's wrong?
c.BindJSON(&input) will happily fill the struct with whatever the user sends—even unwanted fields. An attacker can abuse this by doing:

{
    "content": "Normal notes",
    "createdTs": "admin",
    "visibility": "SECRET",
    "userId": 1,
    "random": "hacker"
}

In earlier versions, such extra fields or malicious values weren’t filtered out or validated, so attackers could change fields they’re not supposed to or crash the app.

Cause confusion, corrupting or deleting memos.

- In some cases, inject unwanted code (depending on further app logic/context).

How Was It Fixed?

From version .13.2, developers added strong input validation and sanity checks. Here’s an example of a patched handler:

// After the fix
func handleMemoCreate(c *gin.Context) {
    var req struct {
        Content    string json:&quot;content&quot; binding:&quot;required&quot;
        Visibility string json:&quot;visibility&quot; binding:&quot;oneof=PRIVATE PUBLIC&quot;
    }

    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(400, gin.H{"error": "Bad input"})
        return
    }

    memo := Memo{
        Content:    req.Content,
        Visibility: req.Visibility,
        // server-controlled fields only, like CreatedTS or UserID
    }
    db.Create(&memo)
    c.JSON(200, memo)
}

Now only allowed fields are accepted, and types are checked.

WARNING: For educational purposes only. Don’t attack systems you don’t own!

Let’s say you’re running a vulnerable version (<.13.2). You could try creating a memo with extra fields:

curl -X POST http://localhost:523/api/memo \
-H "Content-Type: application/json" \
-d '{"content":"hack","userId":9999,"visibility":"PUBLIC"}'

Expected on vulnerable: The API would set userId to 9999, publishing a memo as user 9999 (if app logic allows).
Expected on fixed: The userId field is ignored or causes an error.

How To Protect Yourself

- Upgrade Immediately to memos .13.2 or newer.

References

- CVE-2023-4698 - GitHub Advisory
- Official Fix Commit
- usememos/memos Releases

Last Words

Bugs like CVE-2023-4698 remind us that no input is safe unless we make it safe! If you run note-taking or self-hosted apps, check for updates and keep your users’ data protected and clean.

Timeline

Published on: 09/01/2023 01:15:00 UTC
Last modified on: 09/01/2023 13:07:00 UTC