Integration · ctem
PlexTrac
Pull PlexTrac CTEM findings, reports, and assessment telemetry into Draxis to drive SLA, remediation-velocity, cadence, and crown-jewel-exposure KRIs.
sourceType: ctem
vendorId: plextrac
auth: api-key
schedule: daily
Manual setup, not part of guided onboarding
This connector requires you to register an app or issue an API token in your own vendor console first, so it sits outside the guided onboarding chat. Follow the steps below in your vendor admin UI, then add the integration from Settings → Integrations in Draxis. The four connectors that are in guided onboarding (Microsoft Entra ID, Microsoft Defender for Endpoint, Google Workspace, GitHub Advanced Security) install via a one-click OAuth popup with no per-customer registration step.
At a glance
| Vendor | PlexTrac |
|---|---|
| Source type | ctem |
| Vendor ID (slug) | plextrac |
| Base URL | per-tenant, see below |
| Auth method | api-key, Authorization: Bearer <PlexTrac API key> |
| Schedule default | daily |
| Availability | New in 2026.05. |
Required scopes & roles
PlexTrac does not expose granular OAuth-style scopes; access is role-based. Provision the service account with the smallest role that grants read-only access to the three resources the connector reads.
- Role: Analyst (built-in) or a custom role with only the permissions below. Admin works but is over-privileged, do not use it.
- Clients: Read (list clients and their metadata)
- Reports: Read (list reports per client, read status / dates)
- Findings: Read (list / search findings; read severity, status, tags, SLA date, and compensating-control text)
- Assets (optional): Read, only needed if your findings carry asset-level tags like
internet-facingorcrown-jewelthat aren’t already mirrored on the finding itself. - No write permissions. The role must not have report-write, finding-edit, or admin-user permissions. Draxis never writes to PlexTrac.
Setup steps
- Create a dedicated service user. In PlexTrac, go to Admin → User Management → Add User. Name it
draxis-connector, use a role-mailbox email (e.g.draxis-connector@yourcompany.com), and set a long random password. - Assign the read-only role. Set the user’s role to Analyst (or your custom read-only role from the previous section). If your tenant uses client-scoped access control, grant read access to every client you want Draxis to measure, cadence and coverage KRIs only reflect clients the service user can see.
- Enable MFA on the service user. Sign in as the service user once, go to My Profile → Security → Multi-Factor Authentication, and enroll a TOTP factor. Treat this like any other privileged account.
- Generate the API key. Still signed in as the service user, go to My Profile → API Keys → Generate New Key. PlexTrac shows the key once, copy it into your password manager immediately. The key inherits the minting user’s role at creation, so minting while logged in as the service user (not an admin) is critical.
- Find your tenant numeric ID. Open any page in the PlexTrac UI and look at the URL: the path contains
/tenant/<numeric>/…. Copy that number, the connector passes it to PlexTrac’s v2 finding-search endpoint. - Confirm the base URL. Most SaaS customers use
https://<your-tenant>.kevlar.plextrac.com/api/v1. Self-hosted customers substitute their internal hostname. Always include the/api/v1suffix.
Example least-privilege role definition (custom role, mirror in PlexTrac):
Role: "Draxis Read-Only"
Description: Read-only access for Draxis CTEM KRI collection
Permissions:
Clients: Read (for listing clients, plextrac_assessment_cadence_gap)
Reports: Read (for listing reports per client, cadence + repeat findings)
Findings: Read (for all 8 KRIs, severity, status, tags, SLA, compensating_controls)
Assets: Read (optional, for asset-tag based crown-jewel detection)
Uncheck everything else, including:
Clients / Reports / Findings / Assets: Create, Update, Delete
Admin / User Management / Role Management
Template / Writeup editing
Wire it into Draxis
- Open Settings → Integrations in your tenant.
- Click Add integration and pick Continuous Threat Exposure (CTEM) as the source type.
- Pick PlexTrac from the vendor dropdown. Draxis auto-fills
api-keyauth and the daily schedule. - In API Base URL, paste your tenant URL (e.g.
https://acme.kevlar.plextrac.com/api/v1). - In Auth Token, paste the PlexTrac API key from step 4 above. Draxis encrypts it server-side with
encryption.keybefore storage. - In Extra Config (JSON), set
{"tenant_id": 12345}using the numeric tenant ID from step 5. - Click Test. Green means Draxis called
GET /clientsuccessfully, credentials are valid and the role grants client-read. - Under KRIs to import, tick the KRIs you want Draxis to manage. All eight
plextrac_*KRIs are checked by default; uncheck any you don’t need. Selected rows are created on save with the seeded thresholds. Unchecking a previously-imported KRI deletes it on save. - Save. The connector runs
dailyby default; use Run now from run history to trigger the first sync immediately.
KRIs produced
| Slug | Meaning | Derivation |
|---|---|---|
plextrac_open_critical_high_past_sla |
Open Critical/High findings past their remediation SLA | Count findings where severity ∈ {critical, high}, status ∈ {open, in_process, reopened}, and age-since-created_at exceeds the per-severity SLA (critical > 7d, high > 30d). SLAs are hardcoded industry defaults, edit SLA_DAYS_BY_SEVERITY in the connector to adjust. |
plextrac_remediation_rate_90d_pct |
% of findings reported in last 90d that are now closed | round(count(closed in last 90d cohort) / count(reported in last 90d) * 100, 1). Closed = status closed | resolved | remediated | fixed. Reports 100% if no findings were reported in the window (nothing to measure). |
plextrac_mttr_critical_days |
Mean days-to-close for Critical findings closed in last 180d | For each Critical finding with closed_at in the last 180d, compute (closed_at − created_at) in days; average them. Returns 0 if no Critical findings closed in the window. |
plextrac_repeat_findings |
Findings re-identified across ≥ 2 reports for the same client | Group findings by (client_id, normalized title); count groups whose distinct report_id set has size > 1. Title normalization lowercases and trims whitespace, different wording between engagements will under-count (improve via taxonomy / finding-type IDs on the PlexTrac side). |
plextrac_assessment_cadence_gap |
Clients with no completed report in the last 365d | For each client, fetch reports via GET /client/{id}/reports. A report is "completed" if status contains final, complete, or published. Count clients whose most-recent completed report is older than 365d, or who have no completed reports at all. |
plextrac_accepted_risk_no_control |
Accepted-Risk findings missing compensating-control text | Count findings where status ∈ {accepted_risk, risk_accepted} and the compensating_controls field is empty or whitespace. Governance signal: risk was accepted without the required justification. |
plextrac_retest_backlog |
Findings awaiting retest verification | Count findings where status ∈ {remediated, pending_retest, awaiting_retest} OR retest_required = true. "Remediated" in PlexTrac means "customer says fixed, waiting for assessment team to verify." |
plextrac_internet_facing_high_sev |
Open High/Critical findings on crown-jewel / internet-facing scope | Count findings where status is open, severity is critical or high, and any finding tag or associated asset tag is one of internet-facing, external, crown-jewel, public-facing (case-insensitive, underscore and hyphen variants). |
Each row is a slug the connector writes to. Draxis creates the matching kri rows automatically when you check them in the KRIs to import section of the integration form, no manual API call or seed script needed. Thresholds shown in the table are the seeded defaults; you can edit them freely in the KRIs tab afterwards.
Vendor quirks
- Base URL is per-tenant. SaaS customers sit on
<tenant>.kevlar.plextrac.com; self-hosted customers vary. The connector does not default the URL, always paste yours, including the/api/v1suffix. - No granular OAuth scopes. PlexTrac uses role-based access; the smallest read-only posture is the Analyst built-in role or an equivalent custom role. Document this explicitly in your access-review records, the vendor cannot enforce per-resource scopes beyond the role.
- API keys inherit the minting user’s role. Generating a key while signed in as an admin gives the key admin reach permanently. Always sign in as the service user first, then generate. (Same trap as Tenable.io.)
- Tenant ID is required for v2 finding search. The
tenant_idin Extra Config drivesPOST /tenant/{id}/findings. On older / smaller PlexTrac instances the legacyPOST /findingsworks without it, the connector falls back automatically iftenant_idis omitted, but v2 is faster and more complete. - Status labels vary by template. PlexTrac lets customers customize status names. The connector matches on common canonical values (
open,in process,closed,remediated,accepted risk) in lowercase with both spaces and underscores. If your tenant uses custom labels (e.g."Fixed - Pending Retest"), edit theRETEST_STATUSES/CLOSED_STATUSESsets in the connector, one-line change each. - Repeat-findings heuristic is title-based. PlexTrac does not always expose a stable finding-type or CVE ID. The connector groups by normalized title per client, which under-counts when the same vulnerability is worded differently between engagements. Accuracy improves if your team standardizes writeup titles (and further if you use PlexTrac’s WriteupsDB / Content Library).
- Compensating-control field location is template-specific. The connector reads
compensating_controls/compensatingControlsat the finding root. If your template captures this in a custom field (e.g.custom_fields.cc), the KRI reports 0 because the field isn’t where expected, customize the reader in the connector. - SLA evaluation is uniform, not per-client. PlexTrac can carry per-client SLA policies; the connector evaluates all findings against one set of thresholds (critical 7d / high 30d / medium 90d / low 180d). SLA is an org policy, not a per-integration config, edit
SLA_DAYS_BY_SEVERITYin the connector if your policy differs. - Cadence gap only sees clients the service user can see. If client-scoped ACLs are in use and the service user lacks read access to some clients, those clients are invisible to the KRI, which will under-count the true cadence problem. Grant the service user global client-read, or accept the scoped view deliberately.
- Pagination bounded. The connector paginates findings up to 200 pages × 200/page = 40,000 findings per run. Very large tenants approaching that ceiling should raise
FINDING_PAGE_CAP, there is no rate-limit risk at daily cadence.
Troubleshooting
- HTTP 401 on Test, API key is wrong, expired, or the service user was deactivated. Re-generate under the service user’s profile.
- HTTP 403 on
/findingsbut/clientsucceeds, the role grants client-read but not finding-read. Edit the role to add Findings: Read. plextrac_assessment_cadence_gapis 0 but you know some clients are overdue, the service user probably doesn’t have read access to those clients. Grant global client-read, or trim the KRI’s scope expectations.plextrac_mttr_critical_days= 0, usually means no Critical findings were closed in the last 180 days. Run log reportsmttr_sample_size, if it’s 0, benign (no data).plextrac_repeat_findingsseems low, title-based grouping under-counts when writeups are worded differently between reports. Standardize titles via the WriteupsDB, or accept the lower bound as a floor.rowsSkipped > 0androwsWritten = 0, your tenant hasn’t imported any KRIs for this integration yet. Open the integration in Settings → Integrations, tick the KRIs under KRIs to import, and save.- Still stuck? Open a support ticket with the run ID (from Run history) and we’ll dig in.