Skip to main content
CMDashCybersecurity Maturity Dashboard
← Back to Custom Connector

Custom Connector — Integration Setup

What this integration is for: every other integration in this catalog names a vendor CMDash has written an adapter for. This one does not. You describe an HTTP/REST source yourself — its URL, how to authenticate, and which fields to read — and CMDash syncs it on a schedule exactly like a built-in connector. No CMDash release, and no waiting for your vendor to be added.

When to use this, and when not to

Use a custom connector when the system you need evidence from has a JSON HTTP API and is not in the catalog: an internal service, a regional vendor, a niche tool, or something your team built.

Do not use it to replace a built-in connector. A built-in adapter normalizes a vendor's data into CMDash's own shapes — vulnerabilities, endpoints, identity coverage — and feeds posture scoring and continuous compliance from them. A custom connector produces ATTESTED-tier maturity observations, which is a deliberately weaker claim (see Evidence tier).

Prerequisites

  • CMDash Command tier or above
  • The custom-connectors feature enabled for your workspace
  • OWNER or ADMIN role
  • A source that returns JSON over HTTPS, reachable from the public internet
  • A credential for that source, if it needs one

Reachability. CMDash's sync workers call your endpoint from the public internet. A source on a private network, behind a VPN, or bound to localhost cannot be reached, and CMDash will refuse to save a URL that resolves to a private or link-local address — this is an anti-SSRF control and is not configurable.

Step 1: Describe the request

  1. Go to Integrations → Custom Connectors → New connector.
  2. Give it a name unique within your workspace, and an optional description.
  3. Enter the endpoint URL. It must be http:// or https:// and must resolve to a public address.
  4. Choose the method (GET by default). If you pick POST, supply a request body template.
  5. Add any static headers your source needs.

Step 2: Choose an auth style

Auth typeWhat you supplyHow CMDash sends it
NONEnothingno credential
API_KEY_HEADERthe key, and header name<Your-Header>: <key> (defaults to X-API-Key)
API_KEY_QUERYthe key, and param name?api_key=<key> (name configurable)
BEARER_TOKENthe tokenAuthorization: Bearer <token>
BASIC_AUTHusername and passwordAuthorization: Basic <base64>
OAUTH2_CLIENT_CREDENTIALSclient id, secret, token URLCMDash mints a token, then sends it as a bearer

Credentials are encrypted at rest through the same key-managed path every other connector's credentials use, and are never returned by any API — once saved, a credential can be replaced but not read back.

Authorization-code OAuth2 is not supported. That flow requires you to register an OAuth application and consent through a browser redirect, which a scheduled server-side sync cannot do. If your source only offers three-legged OAuth, it needs a real adapter — tell CMDash support which source it is.

Step 3: Map the fields

A mapping has three parts: a JSONPath into the response, a target field name, and where the value lands.

CMDash supports a deliberately narrow JSONPath subset:

SyntaxMeaning
$the whole response
.namean object member
['name']an object member whose name needs quoting
[0]an array element by index
[*]every element of an array or object

Filter expressions ([?(...)]), recursive descent (..), slices ([1:3]) and unions ([0,1]) are not supported and are rejected when you save. This is a security decision, not an omission: those are the constructs that make a JSONPath engine evaluate code, and a mapping you author runs on CMDash's servers. A path using one of them fails immediately with an explanation, rather than quietly matching nothing at 3am.

Examples against {"data":{"items":[{"id":"a","score":1}],"total":1}}:

code
$.data.total            -> 1
$.data.items[0].id      -> "a"
$.data.items[*].score   -> [1]

Where a mapped value lands

Each mapping lands as a maturity observation:

  • Observation — the value becomes a MaturityObservation under a source class you pick from a fixed list. Observations flow into maturity scoring and continuous compliance. The list is fixed on purpose: a source class is part of CMDash's scoring vocabulary, so a tenant selects an existing one rather than inventing a label that nothing downstream understands.
  • There is no Evidence destination. An earlier version of the builder offered one, but it never stored anything: a compliance evidence record has to name the framework and control it supports, and a mapped value has none. The builder now refuses it, and a connector saved with one still syncs but reports each such mapping as ignored (the sync shows as partial). If no source class describes your field, attach the supporting file to the control as evidence yourself.

Step 4: Dry-run before you save

Dry run issues the real request against your real endpoint and shows you the raw response alongside what each mapping extracted — but writes nothing. Use it until every mapping resolves. A mapping that matches nothing is reported as a mapping error, not silently skipped.

Step 5: Schedule

Pick a sync interval. Custom connectors get their own rate-limit budget and their own circuit breaker per connector, so a flaky endpoint slows or trips only itself and never the rest of your integrations.

Evidence tier

Every observation a custom connector produces is recorded at the ATTESTED tier — the same tier as something a person typed in — never OBSERVED or VALIDATED.

This is deliberate and is not a limitation to work around. CMDash cannot corroborate a source it knows nothing about; a connector can be pointed at any URL that returns agreeable JSON. Treating self-configured data as independently observed would let a workspace raise its own credibility score by pointing a connector at a file it wrote. Auditors ask where a number came from, and "a source the customer configured themselves" is the honest answer.

Limits

  • Response bodies are capped at 2 MiB.
  • A single [*] mapping yields at most 1,000 values.
  • Redirects are never followed automatically.
  • Each sync makes ONE request to your endpoint (no paging): if your API paginates, the mapped values come from the first page only. Point the connector at an endpoint that returns the whole summary you need.
  • Inbound webhooks are not supported — CMDash polls your source; your source cannot push to CMDash. (For push-based ingest, see the signed evidence-push API.)
  • Continuous-compliance rules cannot yet target a specific custom connector when a workspace has more than one. This is known and tracked.

Troubleshooting

SymptomCause
"URL host resolves to a private address"The endpoint is not publicly reachable. This is an anti-SSRF control.
"target did not return valid JSON"The source returned HTML or plain text — often an auth page.
"matched nothing in the response"The JSONPath is right-looking but wrong. Re-run a dry run and compare.
"circuit breaker open"This connector failed repeatedly and is cooling off. Only it is affected.
Invalid JSONPath on saveYou used a filter, slice, union or ... Rewrite it as an explicit path.

Ready to see your posture?

Start a 30-day free trial of any paid plan — a card is required, and it converts unless you cancel — or sign up for Free with no card at all.