CVE-2026-50553
Summary
Note Mark validates book and note slug values with the OpenAPI/huma tag pattern:"[a-z0-9-]+". huma compiles this with regexp.MustCompile(s.Pattern) and tests it with patternRe.MatchString(str), an UNANCHORED match. Because the pattern is not anchored (^...$), any string that merely CONTAINS one [a-z0-9-] substring passes validation. A slug such as ../../../../../../tmp/escape is accepted and stored verbatim.
The data-export CLI commands (note-mark migrate export and note-mark migrate export-v1) join these unsanitized slugs straight into the output path with path.Join / filepath.Join, then os.MkdirAll the directory and os.Create the note file. path.Join resolves the ../ segments, so the note content file is written OUTSIDE the configured export directory. The export process commonly runs as root (default in Docker / bare-metal admin usage), so this is a root-privilege arbitrary directory create + file write.
This is the unguarded sibling of GHSA-g49p-4qxj-88v3 (CVE class CWE-22 in the same export sinks). That fix added filepath.Base(asset.Name) to sanitize the asset filename, but the adjacent path components book.Slug and note.Slug — used in the very same path.Join calls in the same two export functions — were left raw, and their input-side pattern guard is bypassable as shown above.
Vulnerable code
Slug input validation (backend/db/types.go, v0.19.4):
type CreateBook struct {
Name string json:"name" required:"true" minLength:"1" maxLength:"80"
Slug string json:"slug" required:"true" minLength:"1" maxLength:"80" pattern:"[a-z0-9-]+"
IsPublic bool json:"isPublic,omitempty" default:"false"
}
type CreateNote struct {
Name string json:"name" required:"true" minLength:"1" maxLength:"80"
Slug string json:"slug" required:"true" minLength:"1" maxLength:"80" pattern:"[a-z0-9-]+"
}
huma applies the pattern UNANCHORED (github.com/danielgtaylor/huma/v2@v2.37.3):
// schema.go
if s.Pattern != "" {
s.patternRe = regexp.MustCompile(s.Pattern)
// validate.go
if s.pa
⚡ Watch CVE-2026-50553
Get an email if CVE-2026-50553 is added to CISA KEV, gains public exploit code, or a new advisory cites it — max one per day, one-click unsubscribe.
Advisory coverage (1)
External references
Embed the live status
— this badge updates automatically when the KEV or exploit status changes. How to embed it →
[](https://www.csirts.com/cve/CVE-2026-50553)