Skip to content

keywordSearch returns 0 for hyphenated terms like use-after-free, cross-site, and CVE IDs #175

Closed

Description

@jgamblin

Searching for a term with a hyphen in it returns nothing in the default (non-exact) mode:

for q in 'use-after-free' 'cross-site' 'CVE-2021-44228' 'log4j-core'; do
  curl -s -X POST https://search.cve.org/search -H 'Content-Type: application/json' \
    -d "{\"keywordSearch\":\"$q\",\"resultsPerPage\":1}" | jq -r --arg q "$q" '"\($q): \(.pagination.totalResults)"'
done
# use-after-free: 0
# cross-site: 0
# CVE-2021-44228: 0
# log4j-core: 0
keywordSearch Default mode With keywordExactMatch: true cvelistV5 descriptions
use-after-free 0 8,968 8,958 contain "use-after-free" or "use after free" (5,206 have only the hyphenated form)
CVE-2021-44228 0 9 9
log4j-core 0 n/a 1
cross-site 0 n/a n/a
node.js / x86_64 1,129 / 227 n/a these work; see below

For comparison, cross site as two words (cross* AND site*) returns 50,459.

Why I think this happens

searchQueryBuilder.js#L216-L217 escapes the term, and addWildCard adds a *, so OpenSearch receives use\-after\-free*.

  • The query side. simple_query_string has analyze_wildcard off by default, so it turns that into a single prefix query on use-after-free. That query gets lowercased, which is why Apache and apache both return 4,010, but it isn't split into words.
  • The index side. The description text, however, was indexed as separate tokens: use, after, and free. No indexed term starts with use-after-free, so nothing matches.
  • Why some punctuation works. This fits the standard tokenizer, which splits on hyphens but keeps node.js and x86_64 together. That's why those two queries do work.
  • Not the escaping. An unescaped use-after-free* behaves the same way, and the escaping from query_string omits escaping of reserved characters #63 should definitely stay.

I know the README describes this behavior ("each whitespace-delimited term receives a trailing prefix wildcard"). The trouble is that the design quietly returns zero for any term the analyzer splits, and that includes CVE IDs, CWE IDs, and a lot of everyday vulnerability vocabulary.

Possible fixes

  • Turn on analyze_wildcard. With default_operator: AND, use-after-free becomes use AND after AND free*. That matches the words in any order rather than as a phrase, but it's far better than zero.
  • For phrase matching, send split terms as match_phrase_prefix, or use multi_match with type: bool_prefix or match_bool_prefix.
  • Add regression tests for hyphenated terms, CVE IDs, and CWE IDs.

Activity

  1. self-assigned this
    on Oct 13, 2026
  2. afoote-mitre commented on Oct 15, 2026

    @afoote-mitre
    Collaborator

    Included in #182

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions