qualys

n8n community node for Qualys VMDR, VMDR OT and CyberSecurity Asset Management

Package Information

Released: this month
Downloads: 0 weekly / 0 monthly
Latest Version: 3.0.2
Author: SYNERGY

Documentation

@synergyconsulting/n8n-nodes-qualys

NPM Version
License: MIT

This is an n8n community node. It lets you use Qualys in your n8n
workflows.

Qualys is a cloud platform for vulnerability management and asset inventory. This node reads
from three of its API surfaces through a single node and a single credential: VMDR, VMDR OT and
CyberSecurity Asset Management.

The package ships two nodes: Qualys, which reads on demand, and Qualys Trigger, which
polls VMDR and starts a workflow when something changes. Both are read-only. Nothing either
does modifies your Qualys subscription.

n8n is a fair-code licensed
workflow automation platform.

Installation
Operations
Trigger
Credentials
Compatibility
Usage
Resources
Version history
Development
License

Installation

Follow the installation guide
in the n8n community nodes documentation, using the package name @synergyconsulting/n8n-nodes-qualys.

To install it manually into a self-hosted instance:

cd ~/.n8n/custom && npm install @synergyconsulting/n8n-nodes-qualys

Operations

Resources group endpoints by what the data is; the operation names the record. Four resources,
26 operations.

OT

Operational technology inventory, from the VMDR OT gateway.

Operation Qualys endpoint
List Host Assets /ot/1.0/host/list
List Vulnerabilities /ot/1.0/detection/list
List Project Files /ot/1.0/projectfile/list

IT Asset

IT inventory, from the CyberSecurity Asset Management gateway.

Operation Qualys endpoint
List Assets /rest/2.0/search/am/asset
Get Asset /rest/2.0/get/am/asset
Count Assets /rest/2.0/count/am/asset
List Software Components /rest/2.0/am/asset/component
Get Software Components /rest/2.0/am/asset/component/{assetId}

VMDR

Vulnerability Management, Detection and Response, on the platform API.

Operation Qualys endpoint
List Detections /api/5.0/fo/asset/host/vm/detection/
List KnowledgeBase /api/4.0/fo/knowledge_base/vuln/
List CVE Scores /api/2.0/fo/knowledge_base/qvs/
List Hosts /api/5.0/fo/asset/host/
List Virtual Hosts /api/2.0/fo/asset/vhost/
List Asset Groups /api/2.0/fo/asset/group/
List Networks /api/2.0/fo/network/
List Domains /api/2.0/fo/asset/domain/
List IP Addresses /api/2.0/fo/asset/ip/
List Excluded Hosts /api/2.0/fo/asset/excluded_ip/
List Scans /api/2.0/fo/scan/
List Scanner Appliances /api/2.0/fo/appliance/
List Reports /api/3.0/fo/report/
List Static Search Lists /api/2.0/fo/qid/search_list/static/
List Dynamic Search Lists /api/3.0/fo/qid/search_list/dynamic/

EASM

External attack surface discovery.

Operation Qualys endpoint
List Profiles /easm/v2/profile
List Unresolved Domains /rest/2.0/am/domain/list
Count Unresolved Domains /rest/2.0/am/domain/count

Endpoint versions are pinned to the ones Qualys still marks Active. Host List and Host List
Detection 2.0 through 4.0 reached End-of-Support in December 2025; Report and Dynamic Search
List have each since moved a version on.

Two operations behave unusually. List IP Addresses and List Excluded Hosts return a
single item holding the whole IP set, because Qualys mixes bare addresses and ranges in the
same container. List Dynamic Search Lists is slow: Qualys evaluates each list's QID query
server-side, and a handful of lists took over two minutes on a small subscription.

Trigger

Qualys Trigger starts a workflow when VMDR reports a change. Qualys has no outbound
webhook for these collections, so the node polls on whatever interval you set.

It is not a separate app in the nodes panel: searching Qualys finds one entry, with these
events under Triggers and the read operations under Actions.

Event Reads Changed-since parameter
Detection Updated /api/5.0/fo/asset/host/vm/detection/ detection_updated_since
Host Scanned /api/5.0/fo/asset/host/ vm_scan_since
KnowledgeBase Updated /api/4.0/fo/knowledge_base/vuln/ last_modified_after
Scan Launched /api/2.0/fo/scan/ launched_after_datetime

Each poll reads one window of time: from where the last poll stopped to the moment this one
started. The mark lives in the node's static data, so restarting n8n resumes rather than
replaying or skipping. The polling settings sit under Options, beside the watch filters.
First Poll Covers (Minutes) sets how far the very first poll reaches back (default 60) — 0
emits only what happens after activation.

Max Records Per Poll (default 1000) caps a single run so a backlog cannot flood the workflow. Nothing is
dropped: the poll remembers Qualys' next-batch URL, the high-water mark stays put, and the
following poll finishes that window before opening a new one. Batches are taken whole, so a
poll can overshoot the cap by up to one Batch Size.

Detection Updated asks for Fixed detections as well as New, Active and Re-Opened — the
API omits them otherwise, and a remediation workflow is usually waiting for exactly that.
It offers the same Item Granularity choice as the node.

Delivery is at-least-once. Qualys' date filters are inclusive, so a record that changes
exactly on a window boundary can arrive twice; key on the record rather than on the fact that
the workflow ran.

Pressing Fetch Test Event in the editor reads the lookback window and deliberately leaves
the stored mark alone, so testing cannot make the live trigger skip records.

Credentials

Create a Qualys API credential.

Platform picks your pod and derives both hosts the node needs — the gateway (gateway.*)
and the platform API (qualysapi.*). Choose Custom for a Private Cloud Platform and enter
the URLs yourself. Help → About in the Qualys UI shows your API server URL. Both URLs must be
HTTPS: the client secret and the token minted from it travel on every request.

One API client authenticates every request. There is no username, no password and no HTTP
Basic fallback — one credential, one mode.

API clients come from User info → View Profile → Auth ID Client Management in the Qualys UI
(requires UI 4.0). Client Type offers User Level, which mints its token at /auth/oidc;
such a client stops working when the user it belongs to is deactivated.

Subscription Level clients (/auth/oauth, which survive user deactivation) are not offered. A
credential saved before they were withdrawn keeps using that endpoint — the transport still
honours the stored setting — but new credentials cannot be pointed at it.

The credential's Test button mints a token against the endpoint your Client Type
selects, so a wrong choice shows up as Invalid Client ID before any workflow runs. Tokens are
cached for their four-hour lifetime and refreshed automatically.

Known gap: IT Asset and EASM domains

These operations do not work yet, and that is a Qualys-side gap. CyberSecurity Asset
Management rejects a client token with 400 Error validating customer from token - Invalid Subscription Id, an error that blames your subscription rather than the credential. Qualys
support confirms client-credential support there is still a work in progress, whatever the
documentation says.

The node sends the client token to Asset Management anyway, so those operations start working
the day Qualys ships it, with nothing to change here. Until then they fail, and the error
explains why rather than sending you to check your entitlements.

Resource Works today
OT yes
VMDR yes
EASM profiles yes
IT Asset, EASM domains not until Qualys ships client auth for CSAM

Permissions

  • API access enabled on the account, and SSO disabled — SSO blocks API authentication
  • VMDR OT needs VMDR OT.API.ACCESS
  • CSAM needs the module enabled and "App API Enabled" on the user's role
  • KnowledgeBase access is granted separately by Qualys Support

Compatibility

Built against n8nNodesApiVersion 1 and requires Node.js 20.15 or later, matching n8n's own
floor. Developed and tested against n8n 1.x.

The package declares no runtime dependencies and ships no third-party code. The Qualys platform
API answers only in XML, so the node reads it with a small parser of its own
(nodes/Qualys/transport/xmlReader.ts); installing the node adds nothing to the n8n instance.

Usage

Filtering

Each plane takes a different filter language, so the node shows the right one per operation.

OT operations use QQL, built from Filter Groups. Rows within a group are bracketed, and
both rows and groups carry their own AND/OR join.

IT Asset and EASM domain operations use the Asset Management criteria document: a flat list
of field/operator/value rows plus one Match setting for the whole list. There is no
nesting, and the operator must suit the field's type or the API answers 400. Use the IN
operator with a comma-separated value for OR within a single field.

Platform operations take Qualys' documented named parameters directly, under Additional
Fields
.
Combinations the API rejects with an opaque 400 — ag_ids with ag_titles, a search list with
qids, qds_min without show_qds — are caught before the request goes out. Anything not
surfaced as a field can be passed through Extra Parameters.

Software Components share the criteria UI, but Qualys splits it into two blocks: rows whose
field starts with component. become the component filter, everything else becomes the asset
filter, and the two are ANDed. It also pages on its own parameter and allows a page size up to
1000 rather than 300.

Paging

Return All pages until the API is exhausted; otherwise Limit caps the result
(default 50).

Each plane pages differently and the node handles all three: page numbers for OT, a
lastSeenAssetId cursor for IT Asset, and the next-batch URL Qualys returns for VMDR. Batch
Size
controls records per VMDR call (default 1000). Setting it to 0 removes the limit, which
Qualys advises against unless you also narrow by an ID or IP range.

VMDR > List KnowledgeBase is the exception. That API takes no batch size and answers with
every matching QID in one response, which in full detail is larger than Node can hold in a
single string. The node therefore walks the QID space in chunks, one request per Chunk Size
(QIDs)
window (default 10,000), stopping at Maximum QID or once a run of windows comes
back empty. Naming QIDs outright sends a single request instead, and Minimum QID /
Maximum QID bound the walk. Lower the chunk size if a response is still too large.

Requests are issued serially. The platform API's concurrency limit is low — 2 on the
subscriptions we measured — so parallel fetching would simply fail.

Output

Options > Output Mode is either one item per record or the raw response, page by page.

VMDR > List Detections additionally offers Item Granularity: one item per detection
with its host context flattened in (the default, and what joins cleanly against the other
operations), or one item per host with detections nested.

Options > Add Response Metadata attaches _qualys to each item with the endpoint, plane,
batch count and the rate-limit headers. It has no effect on a raw response.

VMDR responses are XML and are converted to JSON with Qualys' quirks handled: CDATA is
unwrapped, <QDS severity="LOW">25</QDS> keeps both parts, attribute-keyed lists such as
QDS_FACTORS and VULN_COUNT become plain objects, self-closing elements and the literal
string "null" become null, and repeated elements stay arrays even when only one is present.
Field names are left exactly as Qualys documents them.

Using upstream data

Every field that carries a value is expression-enabled, so it can be driven from an upstream
node: Asset ID, CVE IDs, filter fields and values, everything under Additional Fields,
and Limit and Batch Size. Only Resource, Operation and the QQL operator/join dropdowns are
fixed, since those drive which fields the panel shows.

Every operation runs once per input item, with parameters resolving against that item. A
List or Count whose query does not depend on its input would then emit the whole result
set once per item; to run it a single time however many items arrive, turn on n8n's own
Execute Once in the node's settings.

Output items carry pairedItem, so n8n can trace each record back to the input that produced
it.

Joining the operations together

  • List Detections.QID → List KnowledgeBase QIDs for descriptions and solutions
  • KnowledgeBase CVEs → List CVE Scores for per-CVE risk scores
  • List Detections.ASSET_ID (enable Show Asset ID) → Get Asset / List Assets
    assetId

Two ways to do the detection → KnowledgeBase join, both valid:

  • One call. Turn on Execute Once and aggregate the QIDs into the QIDs field:
    {{ $input.all().map(i => i.json.QID).join(',') }}. Cheapest, and the API accepts a list.
  • One call per detection. Leave Execute Once off and set QIDs to {{ $json.QID }}. Slower,
    but each output row pairs with its detection.

Errors

Failures keep everything diagnostic and nothing secret.

The message is what Qualys said, with an actionable hint appended rather than substituted:

Error validating customer from token - Invalid Subscription Id. The Asset Management API
does not accept API client credentials yet, and reports that as a subscription problem.
Qualys support has confirmed client support there is still a work in progress; this node
is already wired for it, so the operation will start working once Qualys ships it.
Nothing to change here.

The description identifies the call without needing to reproduce it:

Request: POST /rest/2.0/search/am/asset
API: CyberSecurity Asset Management
Authenticated with: API client
HTTP status: 400
Qualys code: FAILED

The payload is the parsed response body, so a workflow can branch on
error.body.responseCode rather than parsing a string. httpCode is set for HTTP failures.

Credentials never appear. A transport failure in n8n arrives as an axios error carrying the
outgoing request, including Authorization; before that is handed on it is sanitized —
credential-bearing keys redacted, Bearer/Basic/JWT patterns stripped from any string,
raw-header and socket internals dropped, reference cycles broken, and size bounded. With
Continue On Fail the same enriched message is emitted as item data.

Resources

Version history

3.0

The parameters now follow n8n's own conventions. Saved workflows lose these settings and fall
back to the defaults
, so check each Qualys node after upgrading:

  • List All and Count are now Return All and Limit. Limit defaults to 50, not 100.
  • Run Once For All Items is gone. List and Count operations now run once per input item,
    as Get always did. Turn on n8n's Execute Once node setting for a single run.
  • Output Mode and Add Response Metadata are now under Options.
  • The Qualys parameters that were under Options are now labelled Additional Fields, on
    VMDR, IT Asset and EASM alike. Only the label changed; their values are kept.
  • On Qualys Trigger, First Poll Covers (Minutes), Max Records Per Poll and Batch
    Size
    are now under Options.

2.2

Adds Qualys Trigger, a polling trigger for VMDR detections, hosts, KnowledgeBase changes
and scans. Existing workflows are untouched: it is a second node, not a change to the first.

List KnowledgeBase now walks the QID space in chunks rather than asking for the whole
KnowledgeBase at once, which failed outright on a response larger than Node can hold in a
string. Naming QIDs still sends a single request.

2.1

The Skip parameter has been removed from the list operations. It discarded leading
records client-side after they had already been fetched, spending API quota to throw data away.
Narrow the query with a filter instead. A workflow that set Skip keeps running — the stored
value is simply ignored, so it now returns the leading records it previously discarded.

The published build is now bundled, so the package declares no runtime dependencies.

2.0

2.0 regrouped the endpoints. Where 1.x had 22 resources that each did one thing, there are now
four resources named for the kind of data, and the operation names the record — `Vulnerability

List Detectionsinstead ofVMDR Detection > List`.

Both parameter values changed, so nodes saved by 1.x will not resolve. Reopen each Qualys
node, reselect the resource and operation, and the fields underneath come back with their saved
values. A node left unmigrated fails at run time with Unsupported operation, not silently.

The credential is simpler too: one API client instead of two. A stored 1.x credential keeps
working — its client 1 becomes the client, and a Subscription Level grant is still honoured
under the old field name — but a client that was only in slot 2 needs re-entering.

Authentication is now the API client and nothing else. The username and password fields are
gone, along with the HTTP Basic fallback, so a credential that carried only those will need an
API client ID and secret.

Development

npm install --ignore-scripts   # see the note below
npm run dev                    # n8n with this node loaded, rebuilding on change

Then open http://localhost:5678 and add a Qualys node to a workflow.

Script What it does
npm run dev n8n-node dev — runs n8n with the node linked, rebuilding on change
npm run build Bundles the publishable artifact into dist (see below)
npm run build:test Unbundled TypeScript build into .test-build, for the test suite
npm run build:watch The same unbundled build, in watch mode
npm run lint n8n-node lint — the verification-equivalent check
npm run lint:house The same ruleset plus this repo's extra strictness
npm run typecheck tsc --noEmit
npm test 174 tests
npm run test:coverage Same, with a 90% line/branch/function gate
npm run format Prettier over the sources, tests and config
npm run release n8n-node release — bumps, tags and pushes

Layout

nodes/Qualys/
  actions/
    resources/    one folder per resource: the endpoint tables
    planes/       one folder per Qualys API plane: filters, paging, parameters
    shared/       what belongs to neither
    router.ts     executes an operation
    description.ts
  transport/      authentication, requests, XML, error shaping

Resources are the UI grouping — what the data is. Planes are the transport grouping — how the
API behaves. They are not the same: IT Asset and EASM both sit on the CSAM plane and share its
filter document and cursor paging, which is why that machinery lives in planes/ rather than
inside a resource folder.

The build

n8n-node build is tsc plus an icon copy, which is not enough here. scripts/build.mjs
bundles each entry point with esbuild, emits declarations, and copies the icons and the
.node.json codex that tsc leaves behind. Community nodes may not ship third-party code, so
tests/bundle.test.cjs asserts the published artifact requires nothing but n8n-workflow and
Node built-ins, and inlines nothing from node_modules.

Requirements

Node 24 or newer for npm run dev. n8n-node dev downloads n8n@latest, and n8n checks
the Node version at startup and exits:

Your Node.js version 22.22.0 is currently not supported by n8n.
Please use a Node.js version that satisfies the following version range: >=24.0.0

Everything else — build, lint, typecheck, test — runs fine on Node 20.15+, which is what
engines declares and what CI uses.

--ignore-scripts

@n8n/node-cli pulls in the whole n8n runtime, which includes native modules — isolated-vm
and cpu-features. Neither is needed to build, lint or test this node, and compiling them
needs a node-gyp toolchain, so a plain npm install fails. CI installs the same way. esbuild
is unaffected: it resolves its binary from the @esbuild/<platform> package, which npm
installs without running scripts.

Tests

The suite is entirely offline: tests/support.cjs stubs n8n-workflow and scripts
helpers.httpRequest, so every code path — authentication, paging, XML parsing, error mapping
— is driven from canned responses rather than a live subscription.

CI

Workflow Trigger What it does
ci.yml pull requests, pushes to main typecheck, both lint passes, tests with the coverage gate
publish.yml version tags (2.1.0, 2.2.0-rc.1, …) publishes to npm with a provenance attestation

Releases are cut locally with npm run release, which lints, builds, prompts for the version
bump, writes the changelog, commits, tags and pushes. Pushing that tag is the only thing that
publishes
— the workflow never bumps a version or creates a tag of its own.

The trigger matches unprefixed tags (2.1.0), the shape release-it writes. Older tags in
this repository are v-prefixed (v2.0.8) and will not fire it; to publish a version already
in package.json, push the tag without the v.

Provenance is what lets n8n verify the package, and npm only produces it when publishing from
this workflow — prepublishOnly blocks a bare npm publish so a release cannot go out without
it. Authentication is either npm Trusted Publishing via OIDC (no stored secret) or an
NPM_TOKEN repository secret; publish.yml documents both.

License

MIT — Copyright (c) 2026 UAB Synergy.

Discussion