Running Scans
Learn how to scan domains, poll for results, and interpret security findings. ComplianceLayer's scanning engine analyzes 15+ security modules to provide a comprehensive risk assessment.
How Scanning Works
When you submit a scan request, ComplianceLayer:
- Queues the job — Returns immediately with a job ID
- Validates the domain — Resolves DNS and checks accessibility
- Runs 15+ modules in parallel — DNS, SSL, headers, ports, WHOIS, DNSSEC, breaches, etc.
- Aggregates results — Calculates weighted score and grade
- Maps to compliance — SOC 2, ISO 27001, NIST, PCI-DSS, HIPAA
Scans typically complete in 30-60 seconds. Poll the job status endpoint to check progress.
Basic Scan
Submit a domain for scanning:
curl -X POST "https://api.compliancelayer.net/v1/scan" \
-H "Authorization: Bearer cl_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "example.com"
}'Polling for Results
Poll the job status endpoint every 2-3 seconds until status is completed:
async function waitForCompletion(jobId, maxWait = 120) {
const startTime = Date.now();
while (Date.now() - startTime < maxWait * 1000) {
const response = await fetch(
`https://api.compliancelayer.net/v1/scan/jobs/${jobId}`,
{
headers: {
'Authorization': `Bearer ${process.env.API_KEY}`
}
}
);
const status = await response.json();
switch (status.status) {
case 'completed':
return status.result;
case 'failed':
throw new Error(`Scan failed: ${status.failure_reason}`);
case 'queued':
case 'running':
await new Promise(r => setTimeout(r, 2000)); // Wait 2s
break;
}
}
throw new Error('Timeout waiting for scan');
}Understanding Results
Score & Grade
The overall score is a weighted aggregate of all module scores, aligned with cyber insurance underwriting risk bands:
- 90-100 (A): Low Risk — Excellent security posture
- 75-89 (B): Low-Medium Risk — Good, minor improvements needed
- 55-74 (C): Medium Risk — Material gaps present, several issues to address
- 35-54 (D): High Risk — Significant vulnerabilities, urgent action required
- 0-34 (F): Critical Risk — Multiple critical security gaps
Risk Levels
Each scan receives a risk_level classification for underwriting context:
- low (90-100): Strong security controls, minimal risk exposure
- low_medium (75-89): Acceptable with minor issues, low-moderate risk
- medium (55-74): Material gaps present, moderate risk
- high (35-54): Significant exposure, high risk
- critical (0-34): Multiple critical issues, very high risk
Module Scores
Each security module has its own score and weight. Weights are based on materiality for cyber insurance underwriting decisions:
Tier 1: Material Controls (85%)
| Module | Weight | Checks |
|---|---|---|
| SSL/TLS | 25% | Certificate validity, expiry, chain, protocols, cipher suites |
| HTTP Headers | 25% | HSTS, CSP (including weak directive detection), CORS misconfiguration, X-Frame-Options |
| DNS/Email | 20% | SPF, DMARC, DKIM (info only), CAA records, MX configuration |
| Open Ports | 15% | Exposed services, dangerous ports (Telnet, FTP, RDP), attack surface |
Tier 2: Secondary Controls (15%)
| Module | Weight | Checks |
|---|---|---|
| Cookie Security | 8% | Secure, HttpOnly, SameSite flags |
| DNSSEC | 5% | DNSSEC signing, chain of trust |
| WAF Detection | 4% | Web Application Firewall presence |
| JavaScript Audit | 3% | Vulnerable JS libraries (only exploitable CVEs) |
Tier 3: Informational Only (0%)
The following modules are included for context but do not affect the score:
| Module | Weight | Purpose |
|---|---|---|
| Subdomains | 0% | Inventory and attack surface mapping |
| Blacklists | 0% | Reputation indicators (outcome not control) |
| Reputation | 0% | Historical reputation data |
| Breach History | 0% | Historical breach exposure |
| WHOIS | 0% | Domain registration details |
| Trackers | 0% | Privacy analysis (not security) |
| Tech Stack | 0% | Technology fingerprinting for OSINT |
Issue Severity
- Critical: Immediate action required — Catastrophic for operations (expired SSL, no SPF/DMARC, exposed admin ports)
- High: Urgent fix needed — Important security gaps (weak TLS, missing HSTS on HTTPS sites)
- Medium: Should address soon — Best practice violations (weak CSP directives, CORS misconfigurations)
- Low: Minor improvement — Defense-in-depth enhancements (X-Frame-Options, cookie settings)
- Info: Informational only — No penalty to score (DKIM auto-detection limitations, SSH on port 22 with key auth)
Full Report Structure
The complete report includes:
{
"domain": "example.com",
"score": 87,
"grade": "B",
"risk_level": "low_medium", // One of: low, low_medium, medium, high, critical
"report_id": "cl_rpt_abc123def456", // Use for PDF generation & public verification
"scanned_at": "2026-03-07T12:00:00Z",
// Individual module results
"modules": {
"dns_email": {
"score": 90,
"grade": "A",
"weight": 0.20,
"issues": [...]
},
"ssl": {
"score": 95,
"grade": "A",
"weight": 0.25,
"issues": [...]
},
"headers": { ... }
},
// All issues sorted by severity
"issues": [
{
"severity": "high",
"finding": "Missing DMARC record",
"remediation": "Add _dmarc TXT record",
"module": "dns_email"
}
],
// Important caveats about the assessment
"caveats": [
"External scanning only - internal controls not assessed",
"DKIM false negatives possible with custom selectors",
"Port scan results depend on Shodan data availability"
],
// Compliance framework mappings
"compliance": {
"soc2": [...],
"iso27001": [...],
"nist": [...],
"pcidss": [...],
"hipaa": [...]
},
// Prioritized action items
"recommendations": [
"Add DMARC record to prevent email spoofing",
"Enable HSTS to enforce HTTPS"
]
}Best Practices
1. Cache Results
Don't scan the same domain repeatedly. Cache results for at least 1 hour to reduce API usage.
2. Use Webhooks
Instead of polling, configure webhooks to receive results when scans complete. This reduces API calls and improves efficiency.
3. Handle Errors Gracefully
try {
const jobId = await startScan('example.com');
const result = await waitForCompletion(jobId);
console.log(`Score: ${result.score}`);
} catch (error) {
if (error.status === 429) {
// Rate limit - wait and retry
console.log('Rate limited, waiting...');
await new Promise(r => setTimeout(r, 60000));
} else if (error.status === 400) {
// Invalid domain
console.error('Invalid domain:', error.message);
} else {
// Other error
console.error('Scan error:', error);
}
}4. Monitor Historical Trends
Track score changes over time to identify security drift. Set up monitoring for critical domains.