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
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.