Skip to content

Manage Third Party Risk

evidentia-wiki-sync[bot] edited this page May 31, 2026 · 2 revisions

Manage third-party / vendor risk

Concentration risk, fourth-party exposure, and due-diligence (DD) cadence are the auditor-facing core of a third-party risk management (TPRM) program. Evidentia keeps a local vendor inventory, computes concentration-risk reports across configurable dimensions, and generates / ingests DD questionnaires (CAIQ, SIG via a licensed template, or a packaged generic baseline). This guide walks the full operator loop with the evidentia tprm command group.

Prerequisites

  • Nothing beyond a working Evidentia install — the vendor inventory is local file-backed persistence (no third-party credentials, no network calls).
  • The store location resolves via, in order: an explicit path, the EVIDENTIA_VENDOR_STORE_DIR environment variable, then a platform default (platformdirs.user_data_dir). For a self-contained demo or a CI run, point it at a scratch directory so you do not touch your real inventory:
export EVIDENTIA_VENDOR_STORE_DIR="$(mktemp -d)/vendor_store"

The xlsx questionnaire output format requires the optional [xlsx] extra (pip install 'evidentia-core[xlsx]'). The sig / sig-lite frameworks additionally require a Shared Assessments licensed XLSX template you supply with --from-template. The json / csv paths below run with no extras.

Concepts at a glance

Field What it drives
--type Vendor type — one of saas, subservice_org, contractor, data_processor, cloud_provider, open_source.
--criticality-tier FFIEC tier — one of critical, high, medium, low. Drives the auto-computed DD review cadence.
--regulatory-classification Comma-separated flags — custody, clearing, model, data_processor, critical_third_party.
--residual-risk-score Integer 125 (0 = unscored).
next_review_due Auto-computed from criticality_tier + last_due_diligence_review unless you override it with --next-review-due.

The concentration-report dimensions (--by) are 4th-party, cloud-provider, criticality-tier, region, regulatory-classification, and service-category, aligned to FFIEC + OCC Bulletin 2013-29 + FRB SR 13-19 expectations.

Step 1 — Add a vendor

evidentia tprm vendor add \
  --name "Acme Cloud Inc." \
  --type saas \
  --criticality-tier critical \
  --owner "alice@example.com" \
  --contract-start-date 2026-01-01 \
  --region "us-east-1" \
  --regulatory-classification "data_processor,critical_third_party" \
  --residual-risk-score 16 \
  --last-due-diligence-review 2026-02-15
✓ Added vendor Acme Cloud Inc. (id: e5dd135b-e489-4a4a-9fa4-f3da59589f71)

The command prints the new vendor's UUID — capture it; later commands (show, edit, dd-questionnaire generate) take that ID. Key flags:

  • --contract-start-date is required (YYYY-MM-DD). It is easy to miss because it sits among the optional date flags, but vendor add will not create a record without it.
  • --name, --type, --criticality-tier, and --owner round out the minimum atomic add. See the table above for the --type and --criticality-tier enum values.
  • Because we passed --last-due-diligence-review, Evidentia auto-computes next_review_due from the criticality-tier cadence (a critical vendor reviewed 2026-02-15 is next due 2027-02-15).
  • For complex records with fourth-parties and evidence pointers, skip the atomic flags and load a YAML file with --from-yaml <path> instead.

Add a couple more so later steps have something to aggregate:

evidentia tprm vendor add --name "Globex Hosting LLC" --type cloud_provider \
  --criticality-tier high --owner "bob@example.com" \
  --contract-start-date 2025-06-01 --region "us-east-1" --residual-risk-score 12

evidentia tprm vendor add --name "Initech Analytics" --type data_processor \
  --criticality-tier medium --owner "carol@example.com" \
  --contract-start-date 2025-09-15 --region "eu-west-1" \
  --regulatory-classification "model" --residual-risk-score 6
✓ Added vendor Globex Hosting LLC (id: c03d3d9e-c2d0-451c-8a6a-fc3fbf541716)
✓ Added vendor Initech Analytics (id: 6e4d2c8d-7c63-4701-83fd-38aeab4b4e6a)

Step 2 — List and inspect the inventory

evidentia tprm vendor list
                          Vendor inventory (3 total)
┌─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬──────┬────┬────┐
│ ID      │ Name    │ Type    │ Critic… │ Owner    │ Next    │ Risk │ 4P │ Ev │
│         │         │         │         │          │ review  │      │    │    │
├─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼──────┼────┼────┤
│ e5dd13… │ Acme    │ saas    │ critic… │ alice@e… │ 2027-0… │   16 │  0 │  0 │
│         │ Cloud   │         │         │          │         │      │    │    │
│ c03d3d… │ Globex  │ cloud_… │ high    │ bob@exa… │ —       │   12 │  0 │  0 │
│         │ Hosting │         │         │          │         │      │    │    │
│ 6e4d2c… │ Initech │ data_p… │ medium  │ carol@e… │ —       │    6 │  0 │  0 │
│         │ Analyt… │         │         │          │         │      │    │    │
└─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴──────┴────┴────┘

The table is sorted by criticality then name. The 4P column counts fourth-parties and Ev counts attached evidence refs. Filter with --criticality-tier / --type to narrow a large inventory.

For machine consumption, add --json — a bare array of vendor records, ready for jq:

evidentia tprm vendor list --json | jq '.[].name'
"Acme Cloud Inc."
"Globex Hosting LLC"
"Initech Analytics"

Each record carries the full vendor shape (id, type, criticality_tier, relationship_owner, region, the contract / review dates, regulatory_classification, fourth_parties, residual_risk_score, evidence_refs, created_at / updated_at, and an evidentia_version stamp). This same JSON is what you feed to gap analysis as a tamper-evident vendor inventory — see What's next.

The CLI --json is unpaginated (optimized for shell pipes). The REST equivalent GET /api/tprm/vendors returns a {total, skip, limit, vendors} pagination envelope instead; the shape divergence is intentional and documented in the CLI reference.

Show one vendor in full, including the resolved review cadence:

evidentia tprm vendor show e5dd135b-e489-4a4a-9fa4-f3da59589f71
Acme Cloud Inc.  (e5dd135b-e489-4a4a-9fa4-f3da59589f71)
  Type:               saas
  Criticality tier:   critical
  Relationship owner: alice@example.com
  Contract start:     2026-01-01
  Contract end:       (indefinite)
  Last DD review:     2026-02-15
  Next review due:    2027-02-15
  Residual risk:      16 / 25
  Regulatory flags:   data_processor, critical_third_party
  Created: 2026-05-30 06:44:33+00:00  Updated: 2026-05-30 06:44:33+00:00

Add --json to show for the raw record instead of the human view.

Step 3 — Edit a vendor record

Atomic --<field> flags update one or more fields in place. Record a completed DD review and bump the residual-risk score for the cloud-provider:

evidentia tprm vendor edit c03d3d9e-c2d0-451c-8a6a-fc3fbf541716 \
  --residual-risk-score 15 \
  --last-due-diligence-review 2026-03-01
✓ Updated vendor Globex Hosting LLC (id: c03d3d9e-c2d0-451c-8a6a-fc3fbf541716)

Updating --last-due-diligence-review re-runs the cadence calculation, so next_review_due moves automatically (a high vendor reviewed 2026-03-01 is next due 2027-03-01). Confirm with show:

evidentia tprm vendor show c03d3d9e-c2d0-451c-8a6a-fc3fbf541716
Globex Hosting LLC  (c03d3d9e-c2d0-451c-8a6a-fc3fbf541716)
  Type:               cloud_provider
  Criticality tier:   high
  Relationship owner: bob@example.com
  Contract start:     2025-06-01
  Contract end:       (indefinite)
  Last DD review:     2026-03-01
  Next review due:    2027-03-01
  Residual risk:      15 / 25
  Created: 2026-05-30 06:44:51+00:00  Updated: 2026-05-30 06:45:35+00:00

edit has two other mutually-exclusive modes: --from-yaml <path> for a scripted full-replace (preserves the original id + created_at), and --editor to open the current record as YAML in $EDITOR. To remove a record entirely, evidentia tprm vendor delete <id> prompts for confirmation unless you pass -y — auditors generally prefer keeping the record and letting the contract dates lapse over deleting history.

Step 4 — Run a concentration-risk report

Aggregate the inventory across one or more dimensions to surface where you are over-concentrated. Pass --threshold to flag any value whose vendor share meets-or-exceeds a percentage; omit it for an unflagged distribution view.

evidentia tprm concentration-report --by criticality-tier --threshold 30 --format json
{
  "generated_at": "2026-05-30T06:45:49.891330Z",
  "total_vendors": 3,
  "threshold": 30.0,
  "dimensions": [
    {
      "dimension": "criticality-tier",
      "total_unique_values": 3,
      "distribution": [
        { "value": "critical", "count": 1, "percentage": 33.3, "exceeds_threshold": true },
        { "value": "high",     "count": 1, "percentage": 33.3, "exceeds_threshold": true },
        { "value": "medium",   "count": 1, "percentage": 33.3, "exceeds_threshold": true }
      ],
      "vendors_with_value": 3
    }
  ]
}

The real JSON also ends with an "evidentia_version" field (the build that produced the report); it is trimmed here so the doc does not pin a version.

The report dict carries generated_at, total_vendors, the threshold you passed, and a dimensions array — each with a per-value distribution (count, percentage, and exceeds_threshold against your threshold). With three single-vendor tiers each holding 33.3%, all three exceed a 30% threshold.

--by accepts multiple comma-separated dimensions (the default is region,cloud-provider), and --format offers html / json / csv. CSV is the most pipe-friendly for a single dimension:

evidentia tprm concentration-report --by region --threshold 50 --format csv
dimension,value,count,percentage,exceeds_threshold
region,us-east-1,2,66.7,true
region,eu-west-1,1,33.3,false

Here two of three vendors sit in us-east-1 (66.7%), which trips the 50% threshold — exactly the regional-concentration signal an examiner looks for. The default --format html writes a self-contained, sortable HTML report; redirect it to a file (--output report.html) or let it dump to stdout.

Step 5 — Generate a due-diligence questionnaire

dd-questionnaire generate pre-fills a questionnaire with the vendor's metadata (name, type, criticality, contract dates, region, regulatory classification, fourth-party disclosures) so the receiving vendor only fills in the control answers. The default framework is evidentia-generic (a packaged FFIEC-aligned baseline) and the default --output-format is json:

evidentia tprm dd-questionnaire generate \
  --vendor-id e5dd135b-e489-4a4a-9fa4-f3da59589f71 \
  --format evidentia-generic \
  --output-format json \
  --output acme-dd.json
✓ Wrote JSON questionnaire to acme-dd.json  (20 question(s);
  format=evidentia-generic; vendor=Acme Cloud Inc.)

The written file carries a vendor metadata block (echoing the inventory record) and a questions array. Each question has a stable id, a domain, the question_text, optional response_options, and operator notes on acceptable evidence:

{
  "id": "EVG-GOV-03",
  "domain": "Governance",
  "question_text": "Has your organization undergone an independent third-party security audit (SOC 2 Type II, ISO 27001, FedRAMP, or equivalent) in the last 12 months?",
  "response_options": ["Yes", "No", "Not Applicable"],
  "notes": "If Yes, provide the report or attestation letter and indicate the audit period covered."
}

Key flags:

  • --vendor-id is required — the questionnaire is always tied to a record.
  • --format choices: caiq-full, caiq-lite, evidentia-generic (packaged). sig / sig-lite are also accepted only with --from-template (see below).
  • --output-format choices: json, csv, xlsx. xlsx requires the [xlsx] extra (pip install 'evidentia-core[xlsx]') and a --output path (binary output can't go to stdout). The json / csv paths shown here need no extra.

Requires a licensed template. SIG / SIG-Lite generation needs a Shared Assessments licensed XLSX you supply with --from-template; Evidentia pre-fills vendor metadata into the standard cells and leaves the question content untouched for license compliance. Not shown here (the template is not redistributable):

evidentia tprm dd-questionnaire generate \
  --vendor-id <id> --format sig \
  --from-template path/to/SIG-2026.xlsx \
  --output sig-prefilled.xlsx

Step 6 — Ingest a completed questionnaire

Once a vendor returns the completed file, dd-questionnaire ingest parses it and correlates it back to the inventory record. Format is auto-detected from the extension (.json / .csv / .xlsx). Correlation is required — it resolves via --vendor-id if you pass it, otherwise via the questionnaire's embedded vendor_id from the prefill.

evidentia tprm dd-questionnaire ingest --questionnaire acme-completed.json

The command parses the file, correlates it back to the vendor inventory record, and prints a summary for operator review:

✓ Ingested questionnaire from completed-q.json
Vendor: Acme Cloud (id=e1ed43f9-…)  Questionnaire ID: ed778a88-…  Format: evidentia-generic
Responses: 20 (answered: 0)
        Vendor responses (first 25)
┌─────────────┬──────────┐
│ Question ID │ Response │
├─────────────┼──────────┤
│ EVG-GOV-01  │ (blank)  │
│ EVG-GOV-02  │ (blank)  │
│ …           │ …        │
└─────────────┴──────────┘

Pass --output-format json for a machine-readable summary. The format field carries the questionnaire framework (evidentia-generic, caiq-lite, …); the responses map is keyed by question ID:

{
  "vendor": { "id": "e1ed43f9-…", "name": "Acme Cloud" },
  "questionnaire_id": "ed778a88-…",
  "format": "evidentia-generic",
  "responses": { "EVG-GOV-01": "", "EVG-GOV-02": "", "…": "" }
}

The flags themselves are straightforward: --questionnaire <path> is required; --vendor-id overrides correlation when the embedded ID is missing or you want to file the response against a different record; --output-format is table (default) or json.

Note on persistence: this release's ingest is parse + correlate + display only. Writing the response into vendor.evidence_refs[] is queued for a follow-up release (pending the evidence chain-of-custody Sigstore signing — see Sign and verify evidence).

What's next

  • Feed the inventory into gap analysis. evidentia tprm vendor list --json > vendors.json produces the inventory that evidentia gap analyze --format oscal-ar --vendor-inventory vendors.json embeds into an OSCAL Assessment Results document (each vendor added to metadata.parties[] and as a SHA-256-hashed back-matter resource). See Run a gap analysis.
  • Track remediation of vendor findings. Roll material third-party gaps into a POA&M with milestone timelines.
  • Run reviews on a cadence. Wire the DD-review schedule into a recurring assessment loop with CONMON deployment.
  • Full flag reference. Every tprm flag, default, and enum is in the CLI reference → evidentia tprm.
  • The data model. The base-model conventions behind the vendor record live in Concepts → Data model.

Got stuck?

  • vendor add exits without creating a record: confirm you passed --contract-start-date (YYYY-MM-DD). It is required and sits among the optional date flags, so it is the most commonly missed argument.
  • Invalid vendor ID format (expected UUID string): show / edit / delete take the full UUID, not the truncated ID shown in the list table. Run evidentia tprm vendor list --json | jq '.[].id' to copy a full ID.
  • xlsx requires the [xlsx] extra (or an import error on openpyxl): the xlsx output format needs pip install 'evidentia-core[xlsx]'. Use json or csv if you don't need a workbook.
  • concentration-report shows everything at 0%/100% or an empty distribution: the report is computed over whatever is in the store. Confirm EVIDENTIA_VENDOR_STORE_DIR points at the inventory you populated (a fresh mktemp -d store starts empty), and that the vendors carry the dimension you asked for with --by (e.g. --by region needs --region set on records).

Clone this wiki locally