Why Run a Certificate Risk Assessment?
Certificate-related outages cost enterprises an average of $300,000 per incident. Yet most organizations have never formally assessed the risk their certificate infrastructure carries. They know certificates exist. They know expiry is bad. But they don’t have a structured view of where risk concentrates.
A certificate risk assessment gives you that view. It answers three questions:
- What certificates do we have?
- Which ones represent risk?
- What do we fix first?
This guide provides the complete methodology, from scoping to final report.
Phase 1: Scoping and Preparation
Define Assessment Boundaries
Before scanning anything, define what’s in scope:
Assessment Scope Definition:
- External/public-facing certificates
- Internal network certificates
- Cloud-managed certificates (ACM, Key Vault)
- IoT/embedded device certificates
- Code signing certificates
- Email/S/MIME certificates
- Client authentication certificates
- VPN/IPSec certificates
- Wi-Fi/802.1X certificates
Stakeholder Identification
| Stakeholder | Role in Assessment | Information Needed From |
|---|---|---|
| CISO / Security Director | Executive sponsor | Budget, authority |
| IT Operations | Infrastructure access | Server lists, network maps |
| DevOps / Cloud | Cloud environment access | AWS/Azure/GCP accounts |
| Network Team | Network certificate access | Load balancers, firewalls |
| Application Teams | Application dependencies | Service mappings |
| Compliance | Regulatory requirements | Audit findings, standards |
Tools Preparation
# Assessment toolkit
sudo apt install nmap openssl jq curl
# Install specialized tools
pip install sslyze
go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install github.com/projectdiscovery/httpx/cmd/httpx@latest
# Verify tools
nmap --version
sslyze --version
subfinder -version
Phase 2: Discovery and Data Collection
External Discovery
#!/bin/bash
# external-discovery.sh
DOMAIN="$1"
OUTPUT="assessment-$DOMAIN-$(date +%Y%m%d)"
mkdir -p "$OUTPUT/external"
echo "=== External Certificate Discovery ==="
# CT Log enumeration
echo "[1/3] Querying Certificate Transparency logs..."
curl -s "https://crt.sh/?q=%.$DOMAIN&output=json" | \
jq -r '.[].name_value' | sed 's/\*\.//g' | \
sort -u > "$OUTPUT/external/ct-domains.txt"
# Subdomain enumeration
echo "[2/3] Running subdomain enumeration..."
subfinder -d "$DOMAIN" -all -silent >> "$OUTPUT/external/ct-domains.txt"
sort -u "$OUTPUT/external/ct-domains.txt" -o "$OUTPUT/external/all-domains.txt"
# Active scanning
echo "[3/3] Scanning active endpoints..."
cat "$OUTPUT/external/all-domains.txt" | \
httpx -silent -tls-grab -json > "$OUTPUT/external/tls-scan.json"
echo "External discovery complete."
echo "Domains found: $(wc -l < "$OUTPUT/external/all-domains.txt")"
echo "Active HTTPS: $(wc -l < "$OUTPUT/external/tls-scan.json")"
Certificate Outage Cost Breakdown
Per-incident cost across three severity scenarios
$8,095
Conservative
$22,260
Moderate (typical)
$44,220
Severe
Internal Discovery
# internal-discovery.ps1 - Windows/AD environment scanning
# 1. Query AD CS for all issued certificates
certutil -view -out "RequestID,CommonName,NotAfter,CertificateTemplate" |
Out-File -FilePath "adcs-inventory.csv"
# 2. Scan internal network ranges for TLS services
$ranges = @("10.0.0.0/16", "172.16.0.0/12", "192.168.0.0/16")
foreach ($range in $ranges) {
nmap -sV -p 443,8443,636,3389,5986 $range -oX "nmap-$($range -replace '/','_').xml"
}
# 3. Check certificate stores on domain-joined machines
$computers = Get-ADComputer -Filter * -Properties Name | Select-Object -ExpandProperty Name
foreach ($computer in $computers) {
Invoke-Command -ComputerName $computer -ScriptBlock {
Get-ChildItem Cert:\LocalMachine\My |
Select-Object Subject, NotAfter, Issuer, Thumbprint
} -ErrorAction SilentlyContinue |
Export-Csv -Append -Path "machine-certs.csv"
}
Cloud Discovery
# AWS Certificate Manager
aws acm list-certificates --region us-east-1 --output json > aws-acm-certs.json
aws acm list-certificates --certificate-statuses EXPIRED INACTIVE --output json \
>> aws-acm-certs.json
# Azure Key Vault (all vaults)
for vault in $(az keyvault list --query '[].name' -o tsv); do
az keyvault certificate list --vault-name $vault -o json >> azure-kv-certs.json
done
# GCP Certificate Manager
gcloud certificate-manager certificates list --format=json > gcp-certs.json
Phase 3: Risk Scoring
Risk Scoring Framework
Each certificate receives a risk score based on multiple factors:
RISK SCORE = Impact × Likelihood × Exposure
Impact (1-5):
- 5 = Customer-facing production service
- 4 = Internal production service
- 3 = Business-critical internal tool
- 2 = Development/staging environment
- 1 = Non-functional/informational
Likelihood (1-5):
- 5 = Expired or expiring in less than 7 days
- 4 = Expiring 7-30 days, no auto-renewal
- 3 = Weak crypto (RSA under 2048, SHA-1)
- 2 = Manual renewal process, 30-90 days out
- 1 = Auto-renewal configured, more than 90 days out
Exposure (1-5):
- 5 = Internet-facing, handles sensitive data
- 4 = Internet-facing, general service
- 3 = Internal but broadly accessible
- 2 = Internal, limited access
- 1 = Isolated/air-gapped system
Automated Risk Scoring Script
#!/usr/bin/env python3
"""certificate_risk_scorer.py - Automated risk scoring for certificate findings"""
import json
import csv
from datetime import datetime, timezone
def calculate_risk_score(cert_data):
"""Calculate risk score for a certificate."""
# Impact score
impact = 1
if cert_data.get('environment') == 'production':
if cert_data.get('internet_facing'):
impact = 5
else:
impact = 4
elif cert_data.get('environment') == 'staging':
impact = 2
elif cert_data.get('business_critical'):
impact = 3
# Likelihood score
likelihood = 1
days_to_expiry = cert_data.get('days_to_expiry', 365)
has_auto_renewal = cert_data.get('auto_renewal', False)
key_size = cert_data.get('key_size', 2048)
sig_algo = cert_data.get('signature_algorithm', 'sha256')
if days_to_expiry <= 0:
likelihood = 5
elif days_to_expiry <= 7 and not has_auto_renewal:
likelihood = 5
elif days_to_expiry <= 30 and not has_auto_renewal:
likelihood = 4
elif key_size < 2048 or 'sha1' in sig_algo.lower():
likelihood = 3
elif days_to_expiry <= 90 and not has_auto_renewal:
likelihood = 2
# Exposure score
exposure = 1
if cert_data.get('internet_facing'):
if cert_data.get('handles_sensitive_data'):
exposure = 5
else:
exposure = 4
elif cert_data.get('broadly_accessible'):
exposure = 3
elif cert_data.get('limited_access'):
exposure = 2
total_score = impact * likelihood * exposure
max_score = 125 # 5 * 5 * 5
normalized_score = round((total_score / max_score) * 10, 1)
return {
'impact': impact,
'likelihood': likelihood,
'exposure': exposure,
'raw_score': total_score,
'normalized_score': normalized_score,
'risk_level': classify_risk(normalized_score)
}
def classify_risk(score):
"""Classify risk level based on normalized score."""
if score >= 8.0:
return 'CRITICAL'
elif score >= 6.0:
return 'HIGH'
elif score >= 4.0:
return 'MEDIUM'
elif score >= 2.0:
return 'LOW'
else:
return 'INFORMATIONAL'
Phase 4: Findings Categorization
Category 1: Expired Certificates
FINDING: Expired Certificates in Production
- Risk Level: CRITICAL
- Count: 7 certificates
- Avg. Days Expired: 23
Affected Systems:
api-gateway.company.com (expired 12 days)
partner-portal.company.com (expired 8 days)
legacy-sso.company.com (expired 45 days)
internal-wiki.company.com (expired 3 days)
monitoring.company.com (expired 67 days)
staging-api.company.com (expired 90 days)
old-cdn.company.com (expired 120 days)
Recommendation: Immediate renewal required
Timeline: 24-48 hours for critical services
Category 2: Weak Cryptography
| Certificate | Algorithm Issue | Current | Required | Risk |
|---|---|---|---|---|
| vpn.company.com | RSA 1024-bit key | RSA-1024 | RSA-2048+ | HIGH |
| mail.company.com | SHA-1 signature | SHA-1 | SHA-256+ | HIGH |
| intranet.company.com | RSA 1024-bit key | RSA-1024 | RSA-2048+ | MEDIUM |
| dev-portal.company.com | SHA-1 signature | SHA-1 | SHA-256+ | LOW |
Category 3: Governance Gaps
Findings:
- 7 different CAs in use with no central governance
- 34% of certificates have no identified owner
- 12 wildcard certificates deployed across 47 servers
- No certificate policy documentation exists
- Auto-renewal configured for only 23% of certificates
- Average time from discovery to renewal: 4.2 days (reactive)
Category 4: Compliance Issues
| Standard | Requirement | Current State | Gap |
|---|---|---|---|
| PCI DSS 4.0 | Strong crypto for cardholder data | 3 weak certs in PCI scope | Non-compliant |
| SOX | Certificate controls documented | No documentation | Non-compliant |
| NIST 800-52r2 | TLS 1.2+ only | 5 endpoints support TLS 1.1 | Non-compliant |
| Internal Policy | 90-day expiry alerts | No alerting exists | Non-compliant |
Phase 5: Report Generation
Executive Summary Template
Certificate Risk Assessment - Executive Summary
- Date: [Assessment Date]
- Scope: [Internal/External/Both]
- Assessed by: [Team/Individual]
Key Findings
- Total certificates discovered: [N]
- Certificates with critical risk: [N] ([%])
- Certificates with high risk: [N] ([%])
- Estimated annual exposure: $[N] based on outage probability
Top 3 Risks
- [Highest risk finding with business impact]
- [Second highest risk finding]
- [Third highest risk finding]
Recommendations
- Immediate: [Action within 48 hours]
- Short-term: [Action within 30 days]
- Strategic: [Action within 90 days]
Investment Required
- Immediate remediation: [Hours/Cost]
- Platform investment: [Cost]
- Ongoing management: [Cost/Year]
Detailed Technical Report Sections
- Methodology
- 1.1 Scope definition
- 1.2 Tools used
- 1.3 Scanning approach
- 1.4 Risk scoring methodology
- Discovery Results
- 2.1 External certificates
- 2.2 Internal certificates
- 2.3 Cloud certificates
- 2.4 Coverage gaps identified
- Risk Analysis
- 3.1 Critical findings
- 3.2 High findings
- 3.3 Medium findings
- 3.4 Low findings
- 3.5 Informational findings
- Compliance Mapping
- 4.1 PCI DSS alignment
- 4.2 SOX control gaps
- 4.3 Industry framework alignment
- Remediation Roadmap
- 5.1 Immediate actions (0-7 days)
- 5.2 Short-term actions (7-30 days)
- 5.3 Medium-term actions (30-90 days)
- 5.4 Strategic initiatives (90+ days)
- Appendix
- 6.1 Full certificate inventory
- 6.2 Raw scan data
- 6.3 Tool configurations
Phase 6: Remediation Prioritization
Priority Matrix
| Low Likelihood | High Likelihood | |
|---|---|---|
| High Impact | P2 — Quick Wins | P1 — URGENT, Fix Now |
| Low Impact | P4 — Monitor | P3 — Plan & Fix |
Recommended Remediation Timeline
| Priority | Action | Timeline | Owner |
|---|---|---|---|
| P1 | Replace expired production certs | 24-48 hours | Security + Ops |
| P1 | Rotate exposed wildcard keys | 48-72 hours | Security |
| P2 | Upgrade weak crypto algorithms | 1-2 weeks | Ops |
| P2 | Establish CA governance policy | 2-3 weeks | Security |
| P3 | Implement auto-renewal | 4-6 weeks | DevOps |
| P3 | Deploy monitoring/alerting | 4-6 weeks | Ops |
| P4 | Full CLM platform deployment | 8-12 weeks | All teams |
Running This Assessment Quarterly
A one-time assessment provides a snapshot. Real risk management requires ongoing assessment:
| Frequency | Activity | Purpose |
|---|---|---|
| Weekly | Automated expiry scanning | Catch approaching deadlines |
| Monthly | New certificate discovery | Detect sprawl |
| Quarterly | Full risk assessment | Update risk posture |
| Annually | Compliance mapping review | Maintain audit readiness |
The goal is to move from quarterly assessments to continuous monitoring — where every new certificate is automatically discovered, scored, and tracked from the moment it’s issued.
About QCecuring
QCecuring helps enterprises run continuous certificate risk assessments through automated discovery, real-time scoring, and proactive alerting. Our platform turns the manual assessment process described here into an always-on capability.
Tags: certificate risk assessment, risk scoring, vulnerability assessment, certificate discovery, compliance, remediation planning, security assessment, PKI audit, enterprise security, risk management