intermediate By Mathias Paulenko

Third-Party Vendor Assessment Template

A structured template for evaluating the security, compliance, and operational posture of third-party vendors before onboarding or renewal.

Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.

Overview

A Third-Party Vendor Assessment Template standardizes how your organization evaluates external service providers before contract signing, integration, or renewal. It gathers evidence about a vendor’s security controls, compliance certifications, operational practices, and business continuity posture so teams can make informed risk decisions.

When to Use

  • Before onboarding a new SaaS, cloud, or infrastructure vendor.
  • During annual security reviews or contract renewals.
  • After a vendor experiences a security incident or breach.
  • When procurement requires a documented risk acceptance process.
  • To compare multiple vendors against the same security criteria.

Prerequisites

  • A defined risk appetite and acceptable control baselines.
  • Legal or procurement support for contract review.
  • Access to the vendor’s security documentation, SOC 2 reports, or penetration test summaries.
  • A stakeholder from engineering, security, and legal for scoring.

Solution

Template

1. Vendor Identification

FieldDescriptionExample
Vendor nameLegal entity nameAcme Cloud Services
Service descriptionWhat the vendor providesManaged Kubernetes hosting
Data accessData the vendor will process or storeCustomer email addresses, logs
Integration typeHow the vendor connects to your systemsAPI, OAuth, SSO
Renewal dateContract expiration2027-12-31

2. Security Posture

Control AreaVendor ResponseEvidence RequestedScore (1-5)
Encryption in transitTLS 1.2+Certificate scan
Encryption at restAES-256Architecture doc
Identity and access managementSSO + MFAConfiguration screenshot
Logging and monitoringSIEM + alertsPolicy document
Incident response24/7 response teamRunbook or contract clause
Vulnerability managementMonthly scansScan report

3. Compliance and Certifications

CertificationStatusExpirationNotes
SOC 2 Type IICurrent2026-09-30Report reviewed
ISO 27001Current2027-03-15Certificate attached
GDPR / privacyCompliantN/ADPA signed
HIPAAN/AN/ANo health data

4. Operational Resilience

TopicQuestionAnswer
Uptime SLAWhat is the guaranteed availability?99.95% monthly
Support responseResponse time for critical issues1 hour
Data residencyWhere is data stored?EU, US-East
Backup and recoveryRPO / RTO targets1 hour / 4 hours
Exit strategyHow is data returned or deleted on termination?Encrypted export within 30 days

5. Risk Scoring Summary

Risk CategoryWeightScoreWeighted Score
Security30%41.2
Compliance25%51.25
Operational25%30.75
Financial10%40.4
Reputational10%30.3
Total100%3.9

6. Decision

OutcomeCondition
ApproveTotal score >= 4.0 and no critical gaps
Approve with conditionsScore 3.0 - 3.9 and gaps can be remediated
RejectScore < 3.0 or critical unmitigated risk

Explanation

The template collects consistent evidence across vendors, which makes it easier to compare risk and justify decisions. Scoring converts qualitative answers into numbers that can be tracked over time and escalated to leadership. The decision section removes ambiguity about whether a vendor can proceed.

Variants

  • Lightweight vendor review: A shorter 10-question checklist for low-risk vendors such as analytics or marketing tools.
  • Critical infrastructure review: A deeper assessment with architectural diagrams, source-code review rights, and on-site audits.
  • AI/ML vendor assessment: Adds questions about model training data, bias, output ownership, and explainability.
  • Renewal-only review: Skips basic onboarding questions and focuses on changes since the last assessment.

What Works

  • Reuse the same template for every vendor to keep comparisons fair.
  • Request evidence, not just yes/no answers.
  • Define a minimum score and mandatory controls before starting the review.
  • Store completed assessments in a central repository for audit trails.
  • Re-evaluate high-risk vendors annually or after major incidents.
  • Include right-to-audit clauses in contracts when risk is high.

Common Mistakes

  • Accepting vendor-provided marketing slides as evidence.
  • Skipping re-assessment during renewals.
  • Failing to track remediation commitments after conditional approval.
  • Assigning scoring to a single person without peer review.
  • Ignoring subcontractors or fourth-party dependencies used by the vendor.

Advanced Solutions

Automated vendor security questionnaire with API checks

Automate initial vendor screening by checking public security APIs and registries before sending the full questionnaire:

import requests
from dataclasses import dataclass, field
from typing import Optional

@dataclass
class VendorSecurityCheck:
    vendor_name: str
    domain: str
    results: dict = field(default_factory=dict)

    def check_dnssec(self) -> None:
        """Check if the vendor domain has DNSSEC enabled."""
        try:
            resp = requests.get(
                f"https://dns.google/resolve?name={self.domain}&type=DNSKEY",
                timeout=10
            )
            has_dnssec = len(resp.json().get("Answer", [])) > 0
            self.results["dnssec"] = "enabled" if has_dnssec else "disabled"
        except Exception:
            self.results["dnssec"] = "error"

    def check_tls(self) -> None:
        """Check TLS configuration via SSL Labs API."""
        try:
            resp = requests.get(
                f"https://api.ssllabs.com/api/v3/analyze?host={self.domain}",
                timeout=15
            )
            data = resp.json()
            self.results["tls_grade"] = data.get("grade", "pending")
            self.results["tls_protocols"] = data.get("protocols", [])
        except Exception:
            self.results["tls_grade"] = "error"

    def check_cps(self) -> None:
        """Check for published Certificate Practice Statement."""
        cps_urls = [
            f"https://{self.domain}/cps",
            f"https://{self.domain}/.well-known/security.txt",
        ]
        for url in cps_urls:
            try:
                resp = requests.head(url, timeout=10, allow_redirects=True)
                if resp.status_code == 200:
                    self.results["security_txt"] = url
                    return
            except Exception:
                pass
        self.results["security_txt"] = "not found"

    def check_breach_history(self) -> None:
        """Check Have I Been Pwned API for known breaches."""
        try:
            resp = requests.get(
                f"https://haveibeenpwned.com/api/v3/breaches?domain={self.domain}",
                headers={"User-Agent": "VendorAssessment/1.0"},
                timeout=10
            )
            if resp.status_code == 200:
                breaches = resp.json()
                self.results["breach_count"] = len(breaches)
                self.results["breaches"] = [b["Name"] for b in breaches[:5]]
            else:
                self.results["breach_count"] = 0
        except Exception:
            self.results["breach_count"] = "error"

    def run_all(self) -> dict:
        self.check_dnssec()
        self.check_tls()
        self.check_cps()
        self.check_breach_history()
        return self.results

# Example usage
vendor = VendorSecurityCheck(vendor_name="Acme Cloud", domain="acmecloud.com")
report = vendor.run_all()
for key, value in report.items():
    print(f"  {key}: {value}")

Vendor risk scoring automation

Automate the weighted risk scoring from the assessment template:

from dataclasses import dataclass
from typing import Dict

@dataclass
class VendorRiskScorer:
    scores: Dict[str, float]  # category -> score (1-5)
    weights: Dict[str, float] = field(default_factory=lambda: {
        "security": 0.30,
        "compliance": 0.25,
        "operational": 0.25,
        "financial": 0.10,
        "reputational": 0.10,
    })

    @property
    def total_score(self) -> float:
        total = 0.0
        for category, weight in self.weights.items():
            score = self.scores.get(category, 0)
            total += score * weight
        return round(total, 2)

    @property
    def decision(self) -> str:
        score = self.total_score
        if score >= 4.0:
            return "APPROVE"
        elif score >= 3.0:
            return "APPROVE_WITH_CONDITIONS"
        else:
            return "REJECT"

    @property
    def critical_gaps(self) -> list:
        gaps = []
        for category, score in self.scores.items():
            if score <= 2:
                gaps.append(f"{category}: score {score}/5 is critical")
        return gaps

    def report(self) -> str:
        lines = ["Vendor Risk Assessment Report", "=" * 40]
        for cat, score in self.scores.items():
            weight = self.weights.get(cat, 0)
            weighted = round(score * weight, 2)
            lines.append(f"  {cat}: {score}/5 (weight: {weight:.0%}, weighted: {weighted})")
        lines.append(f"\n  Total Score: {self.total_score}/5.0")
        lines.append(f"  Decision: {self.decision}")
        if self.critical_gaps:
            lines.append(f"  Critical Gaps: {', '.join(self.critical_gaps)}")
        return "\n".join(lines)

from dataclasses import field

# Example usage
scorer = VendorRiskScorer(scores={
    "security": 4,
    "compliance": 5,
    "operational": 3,
    "financial": 4,
    "reputational": 3,
})
print(scorer.report())

Continuous vendor monitoring with scheduled checks

Set up a scheduled CI job to monitor vendor security posture changes between formal assessments:

# .github/workflows/vendor-monitoring.yml
name: Vendor Security Monitoring
on:
  schedule:
    - cron: "0 6 * * 1"  # Weekly Monday 6am
  workflow_dispatch:

jobs:
  monitor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Install dependencies
        run: pip install requests pyyaml
      - name: Run vendor checks
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
        run: |
          python scripts/vendor_monitoring.py \
            --config vendor-registry.yaml \
            --notify slack
# vendor-registry.yaml
vendors:
  - name: "Acme Cloud Services"
    domain: "acmecloud.com"
    risk_level: high
    renewal_date: "2027-12-31"
  - name: "Analytics Pro"
    domain: "analyticspro.com"
    risk_level: low
    renewal_date: "2026-09-15"

SOC 2 Scope Verification Checklist

  • Report covers the specific service you will use
  • Report period is current (within last 12 months)
  • Trust criteria match your requirements (Security, Availability, Confidentiality, Processing Integrity, Privacy)
  • No qualified opinion or material exceptions
  • Description of system matches actual architecture

Frequently Asked Questions

What if a vendor refuses to share a SOC 2 report?
Request a summary of controls or a compliance questionnaire. If they still refuse, escalate the risk and consider requiring a contractual right-to-audit or additional security controls.
How often should vendors be reassessed?
Annually for high-risk vendors, and at every renewal or major service change for others. Incident-triggered reviews are also recommended.
Who should own the assessment process?
Security or risk teams usually own the process, but procurement, legal, and engineering must provide input. Final approval should involve the data owner.