Search syntax
One query language, three doors: the search box on the homepage, the
term parameter on GET /api/v1/vulnerabilities/search,
and the TAXII /search/ the STIX explorer calls. Same parser, same rules, same
errors. This page is the complete reference - every qualifier, how they combine, and the
queries worth stealing.
On this page: How it resolves · Boolean structure · Free text · Qualifier reference · Worked queries · Errors · Input handling
Structured first, text last. A term carrying a qualifier is answered from an indexed
column - product:log4j resolves the product to its component ids and probes the
affected table, it never reads a description. Free text is the fallback for the part of the
query that named no qualifier, which is why a precise query is also the fast one.
Four consequences worth knowing before you write anything complicated:
- Ordinary results are CVEs and malicious packages. Advisory restatements stay hidden
so product and version searches do not repeat the same vulnerability as sparse vendor rows.
Enter an advisory id such as
RHSA-2026:56097and it resolves to the CVE or CVEs it covers. Usetype:osv_advisoryonly when you want advisory records themselves. - A qualifier is a closed set. A name outside it is a
400that names the problem and suggests the nearest match. It is never accepted and quietly dropped. - Sibling software qualifiers must describe the same row.
product:openssl version:<3.0means one affected entry that is both, not an OpenSSL CVE that happens to also mention a version somewhere. - A bare
version:is refused. Nobody searches "anything below 2.15" across a million records and means it; scope it with a product, vendor, purl or ecosystem.
| Form | Example | Meaning |
|---|---|---|
| implicit AND | kev:true has:fix | Adjacent terms both have to match. This is the default. |
OR | kev:true OR ransomware:true | Either side matches. |
NOT | kev:true NOT ssvc:active | Negates what follows, and binds to a whole qualifier, a phrase or a group - not just to a word. - and ! are accepted shorthand for the same thing; this page spells out NOT because a leading hyphen is easy to misread beside ids and hyphenated words. |
| grouping | (origin:CN OR origin:RU) vendor:microsoft | Parentheses set precedence. Nesting is bounded at 16 deep. |
| phrase | "use after free" | Quoted text is handled as one unit. Its main job is passing a value that contains a space to a qualifier - malware:"cobalt strike", tactic:"credential access". As free text a quoted phrase resolves to its weakness class where one exists (see below), never to a substring scan. |
Precedence, loosest to tightest: OR < AND <
NOT < a single term. So a OR b c reads as
a OR (b AND c). When in doubt, use parentheses - they cost nothing.
OR. Because
OR binds loosest, heap OR buffer overflow reads as
heap OR (buffer AND overflow) - not what you meant, and buffer on its
own matches almost nothing. Write heap OR "buffer overflow".Repeating a qualifier inside one AND group ORs its values, which is usually what you meant:
ecosystem:npm ecosystem:pypi is "either ecosystem", not "both at once", because
no package is both.
Anything with no qualifier goes to a term index built over descriptions, summaries, alias
ids, vendor and product names, package names, reference text and sources, repository names and
actor names. Matching is exact on the token - there is no stemming, so
logging and logged are different terms.
Very common words are not in the index. Any free-text term appearing in more than
20,000 records is pruned, among them remote, execution,
overflow, sql and xss. Vendor, product and package
names are exempt and always indexed, so linux still matches everything it names
however common it is. The pruned words were never useful as filters - a word that matches a
third of the corpus does not narrow anything - and every one of them has a better structured
form:
| Instead of | Write | Why |
|---|---|---|
xss | cwe:xss | The weakness class, not the word. 51,631 CVEs. |
sql injection | cwe:sqli | CWE-89 directly. |
remote code execution | cwe:rce attack_vector:network | The weakness plus the vector, which is what the phrase means. |
buffer overflow | cwe:overflow | CWE-787/121/122/190 as one class. |
use after free | cwe:uaf | CWE-416. 8,748 CVEs. |
The common phrases are recognised and expanded for you, quoted or not -
"use after free", "remote code execution",
"privilege escalation", "denial of service",
"authentication bypass", "information disclosure",
"type confusion", "race condition",
"server side request forgery", "hardcoded credentials" and a
dozen more. The response says which expansion ran, so the answer is never a guess you
cannot see.
Class names typed bare resolve on their own. Anything the cwe:
qualifier accepts also works as a plain word when the word itself is not indexed, so
heap, uaf, cmdi, dos, idor,
lfi, oob and priv-esc all answer as their weakness
class rather than as nothing.
Type the prose form anyway and the engine answers with the expansion it ran, or a
400 naming the word and the qualifier to use instead. Words that are specific
enough to be useful stay in the index and work normally: log4shell,
rce, traversal, deserialization, tplink.
Numeric fragments also match ids. A token containing a run of three or more digits
searches ids as well as text, so 44228 finds CVE-2021-44228. Full ids are
exact-matched on a fast path.
Identity - what the software is
Matched exactly against indexed identity columns, case-insensitively. Siblings inside one AND group must describe the same affected row.
| Qualifier | Example | Notes |
|---|---|---|
vendor: | vendor:microsoft | Exact vendor. |
product: | product:log4j | Exact product, or the package name for anything that has no product - every OSV, distro and malicious-package entry. product:spoint finds the malicious npm package. |
purl: pkg: | pkg:pkg:npm/lodash | Full PURL or a bare package name. |
cpe: | cpe:2.3:a:apache:http_server:2.4.50 | Full CPE 2.3, or the vendor:product[:version] shorthand. |
ecosystem: eco: | ecosystem:npm | Package ecosystem. Hierarchical values match by prefix. |
version: ver: | product:log4j version:<2.15 | Range-aware and per-ecosystem, so npm, Maven and Debian orderings each behave correctly. Supports < <= > >=, exact and lo..hi. Refused unqualified. |
Scores and counts
Bare value means "at least". > >= <
<= and lo..hi ranges all work.
| Qualifier | Example | Notes |
|---|---|---|
epss: | epss:>0.9 | EPSS probability, 0-1. |
percentile: | percentile:>0.99 | EPSS percentile. |
cvss: | cvss:>=9 | Headline CVSS. cvss_version: says which version produced it. |
exploits: | exploits:>5 | Exploit evidence count - repositories plus scoring references. It counts evidence, not working exploits. |
refs: | refs:>3 | Reference count. |
repos: stars: forks: | stars:>500 | Linked exploit repositories, and their best stars / forks. |
risk: | risk:>1.5 | Composite risk. The scale is 0-2, not 0-10. |
Exploitation state
| Qualifier | Example | Notes |
|---|---|---|
exploited: | exploited:true | Exploited in the wild, from any source - not only KEV. |
kev: | kev:true | In the CISA KEV catalogue. |
ransomware: | ransomware:true | Known ransomware use. |
weaponized: | weaponized:true | Reliable weaponized tooling exists. |
maturity: | maturity:weaponized | The ladder: none · poc · weaponized · active. |
tte: | tte:<7 | Days from publication to the first public exploit artifact - weaponized exploit code or a CISA KEV listing. Negative means the artifact predates the advisory. |
zeroday: 0day: | zeroday:true | Exploited on or before the publication date. |
ssvc: | ssvc:active | CISA's own SSVC exploitation call: none · poc · active. 183,393 CVEs adjudicated - useful precisely where it disagrees with the line above. |
ssvc_automatable: | ssvc_automatable:true | CISA's automatability call. |
Trending and EPSS movement
epss: is a level. These are the change, which is the question that
answers "what happened this week".
| Qualifier | Example | Notes |
|---|---|---|
trend: | trend:trending | trending · rising · active · stagnant. trending:true and rising:true are the boolean forms of the top two. |
trend_score: | trend_score:>30 | The score behind the tier. |
epss_change: epss_7d: | epss_change:>0.1 | 7-day EPSS delta. Negatives accepted: epss_7d:<-0.1 is "collapsing". |
epss_30d: | epss_30d:>0.2 | 30-day delta. |
epss_trend: | epss_trend:up | up · down · flat, without picking a threshold. The cut is ±0.01, which is measured rather than chosen: the overwhelming majority of positive deltas are under 0.001 and are rounding, not movement. |
Observed probing
Sensor telemetry: hosts were probed for this CVE. It is exposure to attempts, not confirmed compromise, and the vocabulary keeps that straight. 1,074 CVEs across 164 countries.
| Qualifier | Example | Notes |
|---|---|---|
observed_in: | observed_in:AE | Probing seen against hosts there. Takes an ISO-2 code, the full country name, or a partial word. |
observed_from: | observed_from:CN | Probing originating there. |
observed: | observed:>100 | Unique probing source addresses. |
observed_days: | observed_days:<3 | How many distinct days it has been seen at all. Probing on 30 separate days is background noise; on 2 it is news. |
scanning: | scanning:up | up · down · flat, last 7 days against the 7 before. The change, not the level. |
Evidence and repositories
What is attached to the record, and what it actually is. 36,821 CVEs carry evidence; 11,053 carry a linked repository.
| Qualifier | Example | Notes |
|---|---|---|
ref_type: | ref_type:exploited | exploited · poc · weapon · reference. |
ref_source: | ref_source:exploitdb | Who reported it. |
ref_since: | ref_since:>2026-07-01 | Evidence published on or after a date. |
repo_role: | repo_role:exploit | What the repository is, judged from its content: exploit · weapon · scanner · detection · writeup · patch · lab. A "PoC" that is a write-up is not exploit code. |
repo_lang: | repo_lang:python | Primary language. |
repo_stars: | repo_stars:>500 | The best-starred linked repository. |
repo_since: | repo_since:>2026-07-01 | A repository created after a date. New exploit code arrives before exploitation, not after it. |
suspicious: | suspicious:true | At least one linked repository is flagged dangerous or scam. |
Advisories, fixes and record shape
| Qualifier | Example | Notes |
|---|---|---|
advisory: | advisory:DSA-5020-1 | Everything one erratum fixes. |
issuer: | issuer:debian | 28 issuers, 860,359 links over 103,674 CVEs - Debian, Ubuntu, Red Hat, SUSE, GitHub, Chainguard and more. |
fixable: | fixable:true | A fixed version exists. |
alias: | alias:GHSA-jfh8-c2jp-5v3q | Exact advisory-alias membership. |
type: | type:malicious_package | cve · osv_advisory · malicious_package. |
malicious: | malicious:true | A malicious-package advisory rather than a vulnerability. |
status: | status:analyzed | NVD record status. |
assigner: | assigner:cve@mitre.org | The CNA that assigned the id. |
cluster: | cluster:CVE-2021-44228 | Near-duplicates: everything grouped with that CVE. The closest thing the data supports to a related-vulnerabilities link. |
Weakness and impact
| Qualifier | Example | Notes |
|---|---|---|
cwe: | cwe:79 · cwe:CWE-416 · cwe:xss,sqli | Numeric id, CWE- id, or a friendly class name. Comma lists are OR-ed. Classes: xss, sqli, injection, rce, cmdi, overflow, uaf, traversal, ssrf, xxe, deserialization, race, csrf, priv-esc, dos, idor, auth-bypass, ssti and more. |
severity: sev: | severity:critical | critical · high · medium · low. |
attack_vector: av: | attack_vector:network | network · adjacent · local · physical. |
cvss_version: | cvss_version:4.0 | Which version produced the headline score. 200,149 CVEs carry two or more. |
nvd_verified: | nvd_verified:true | NVD analysed the record rather than passing the CNA's data through. |
automatable: | automatable:true | Automatable exploitation. |
initial_access: | initial_access:true | Automatable specifically for initial access. |
post_exploit: | post_exploit:true | Automatable post-exploitation. |
Time
| Qualifier | Example | Notes |
|---|---|---|
age: | age:<30 · age:>365 · age:30..90 | Days since publication. Bare or < = within the last N days; > = older than N. |
published: | published:2024 · published:>=2024-01-01 | A date or a bare year. Ranges with ... |
modified: | modified:>2026-07-13 | The record's own last-modified date. |
added: | added:>2025-01-01 | CISA KEV date-added, so results self-scope to KEV. |
Attribution and ATT&CK Pro
These read who is using the vulnerability, so they are the tier boundary: below Pro
they return 403 naming the qualifier. The gate is on the compiled query, not on
the text, so an ordinary search that merely mentions an actor's name is unaffected.
Everything else on this page is open to any authenticated caller.
| Qualifier | Example | Notes |
|---|---|---|
actor: | actor:qilin · actor:"midnight blizzard" | Word match, so actor:apt finds APT29 without also matching unrelated text. |
origin: | origin:RU · origin:russia · origin:korea | Where the actor is from. ISO-2 code, full name, or a partial word - origin:korea resolves to KP and KR. |
target: | target:AE · target:"united arab emirates" | Who they hit. Same three input forms. |
sector: | sector:healthcare | Targeted industry, from a 24-value taxonomy. |
motivation: | motivation:espionage | Why: espionage, financial, hacktivism, destruction, unknown. |
ttp: technique: | ttp:T1190 · ttp:"public-facing" | ATT&CK technique by id or name. Matches if either view contains it: the CVE's own CWE→CAPEC→ATT&CK chain, or the playbook of an actor attributed to it. |
tactic: | tactic:TA0006 · tactic:"credential access" | ATT&CK tactic by id or name. |
capec: | capec:CAPEC-233 | CAPEC pattern by id or name. |
malware: | malware:plugx · malware:"cobalt strike" | An attributed actor is recorded using it. Names match the MITRE form, the plain form, or any recorded synonym - malware:plugx finds PlugX - S0013. |
tool: | tool:psexec · tool:mimikatz | Same, for tooling. |
malware:true keeps its published
meaning - is this record a malicious-package advisory - while malware:<name>
searches the arsenal. A boolean is never an arsenal name, so the two cannot collide.Existence shorthands
has:exploit · has:poc · has:kev ·
has:ransomware · has:weaponized · has:malicious ·
has:refs · has:repo · has:fix.
Aliases
| Short form | Canonical |
|---|---|
pkg: package: | purl: |
sev: | severity: |
eco: | ecosystem: |
ver: | version: |
av: | attack_vector: |
epss_delta: | epss_change: |
scanned_in: scanned_from: | observed_in: observed_from: |
0day: | zeroday: |
vuln_type: cve_type: | type: |
Each of these runs as written. The ones marked Pro need the attribution tier.
Triage - what to do on Monday
| Question | Query |
|---|---|
| Exploited right now, and I can actually fix it | exploited:true has:fix |
| Exploited, no fix - compensating controls only | exploited:true NOT fixable:true |
| Where CISA and our evidence disagree - they say active, we have nothing | ssvc:active NOT has:exploit |
| The reverse: we see weaponized tooling, CISA has not adjudicated | maturity:weaponized ssvc:none |
| Fast-exploitation shapes, so the patch window is the real constraint | tte:<7 severity:critical |
| Exploited before it was even published | zeroday:true age:<365 |
Early warning - before it is on a list
| Question | Query |
|---|---|
| New exploit code appeared this month for something old and unloved | repo_since:>2026-07-01 age:>365 NOT kev:true |
| Probing is rising and code just landed - the two signals together | scanning:up repo_since:>2026-07-01 |
| EPSS moved hard this week and it is not already famous | epss_change:>0.1 NOT kev:true |
| Being probed here, in the last few days only, not background noise | observed_in:AE observed_days:<3 |
| Real weaponized code, not a write-up mirror | repo_role:weapon repo_stars:>100 |
| Trending, and the reason is evidence rather than chatter | trend:trending ref_type:exploited |
Estate - scoped to what you run
| Question | Query |
|---|---|
| Is this exact dependency version affected? | product:openssl version:3.0 |
| Everything below the fixed release, in one ecosystem | pkg:pkg:maven/org.apache.logging.log4j/log4j-core version:<2.17.1 |
| npm supply-chain risk that is not just a vulnerability | ecosystem:npm type:malicious_package |
| My Microsoft estate, exploited, network-reachable | vendor:microsoft exploited:true attack_vector:network |
| Which single Debian erratum closes the most exposure | issuer:debian exploited:true |
| Everything one advisory covers | advisory:DSA-5020-1 |
| Near-duplicates of a CVE I already triaged | cluster:CVE-2021-44228 |
Threat-led Pro
| Question | Query |
|---|---|
| Nation-state pressure on my Microsoft estate | (origin:CN OR origin:RU) vendor:microsoft exploited:true |
| GCC-targeted and exploited in the wild | (target:"united arab emirates" OR target:"saudi arabia" OR target:qatar OR target:kuwait OR target:bahrain OR target:oman) exploited:true |
| Espionage against government, still unpatched | motivation:espionage sector:government NOT has:fix |
| Initial-access plays with real probability behind them | tactic:"initial access" exploited:true epss:>0.5 |
| Perimeter exploitation, exploited, with a fix | ttp:T1190 exploited:true fixable:true |
| What a specific toolset is being used against | malware:"cobalt strike" exploited:true |
| Credential-access tooling, network-reachable, critical | tool:mimikatz attack_vector:network severity:critical |
Composite - the queries worth saving
| Question | Query |
|---|---|
| Genuinely urgent. Exploited, automatable, network-reachable, and a fix exists - the intersection where patching beats everything else you could do today. | exploited:true automatable:true attack_vector:network has:fix |
| Rising, not risen. EPSS climbing and probing climbing, but not yet on KEV - the window where acting early is still worth something. | epss_trend:up scanning:up NOT kev:true |
| Quiet but armed. Weaponized code exists and nobody has written it up - low noise, real capability. | repo_role:weapon refs:<3 NOT kev:true |
| Ransomware-adjacent, patchable. | ransomware:true has:fix severity:critical |
| Fresh critical exposure in your ecosystem. | ecosystem:npm severity:critical age:<30 has:fix |
| Old, still exploited, still unfixed. The debt that keeps costing. | age:>1095 exploited:true NOT fixable:true |
Silence is the worst answer a search engine can give, so the parser prefers an error over an empty page.
| Input | Response | Why |
|---|---|---|
banana:true | 400 | Not a qualifier. Returns the nearest registered name. |
kev:maybe | 400 | Wrong value type - kev: wants a boolean. |
version:<2.15 | 400 | Unscoped. Add a product, vendor, purl or ecosystem. |
actor:qilin below Pro | 403 | Names the qualifier that gated it. |
xss | 400 | Pruned class word. Suggests cwe:xss. |
| a 40-deep nest, or a 500+ rune term | 400 | Bounded on purpose. |
What you will not get is 200 with an empty list because something you typed was
quietly discarded. Every accepted qualifier runs.
Every query is normalised before it is parsed, so copy-paste behaves:
- Fullwidth and other compatibility forms fold to their ordinary spelling, so
kev:trueiskev:true. - Zero-width characters, bidi overrides and byte-order marks are removed - a zero-width space inside a qualifier name would otherwise turn it into a word that matches nothing.
- An en or em dash inside a word becomes a hyphen, so an id pasted out of a document that
typeset it -
CVE-2026–59310- still resolves to the CVE. A dash with space around it is left alone, because-on its own is the negation prefix. - Newlines, tabs and every Unicode space collapse to a single separator, so a query pasted from a wrapped terminal line or a multi-line list still parses as separate terms.
- Invalid UTF-8 is dropped rather than passed through.
- Terms are bounded at 500 characters, individual values at 256.
Values never reach SQL as text - every one is a bound parameter - so quotes, semicolons and comment markers in a search term are just characters to match on.
Same syntax, programmatically. Is it being exploited right now?
