At a glance

VendorPlexTrac
Source typectem
Vendor ID (slug)plextrac
Base URLper-tenant — see below
Auth methodapi-keyAuthorization: Bearer <PlexTrac API key>
Schedule defaultdaily
AvailabilityNew 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-facing or crown-jewel that 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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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/v1 suffix.

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

  1. Open Settings → Integrations in your tenant.
  2. Click Add integration and pick Continuous Threat Exposure (CTEM) as the source type.
  3. Pick PlexTrac from the vendor dropdown. Draxis auto-fills api-key auth and the daily schedule.
  4. In API Base URL, paste your tenant URL (e.g. https://acme.kevlar.plextrac.com/api/v1).
  5. In Auth Token, paste the PlexTrac API key from step 4 above. Draxis encrypts it server-side with encryption.key before storage.
  6. In Extra Config (JSON), set {"tenant_id": 12345} using the numeric tenant ID from step 5.
  7. Click Test. Green means Draxis called GET /client successfully — credentials are valid and the role grants client-read.
  8. 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.
  9. Save. The connector runs daily by default; use Run now from run history to trigger the first sync immediately.

KRIs produced

SlugMeaningDerivation
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/v1 suffix.
  • 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_id in Extra Config drives POST /tenant/{id}/findings. On older / smaller PlexTrac instances the legacy POST /findings works without it — the connector falls back automatically if tenant_id is 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 the RETEST_STATUSES / CLOSED_STATUSES sets 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 / compensatingControls at 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_SEVERITY in 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 /findings but /client succeeds — the role grants client-read but not finding-read. Edit the role to add Findings: Read.
  • plextrac_assessment_cadence_gap is 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 reports mttr_sample_size — if it’s 0, benign (no data).
  • plextrac_repeat_findings seems 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 > 0 and rowsWritten = 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.