Security Rating

GET /api/v1/perimeter/rating

Security Rating

Overview

The Security Rating endpoint delivers a quantified security assessment for any domain, expressed as both a letter grade (A through F) and a numeric score (300-900). This rating aggregates evidence from the Attack Surface Discovery system across multiple security dimensions: network security, application security, DNS health, email security, certificate management, and vulnerability exposure.

The rating methodology is designed to be comparable to commercial security rating platforms such as BitSight (250-900 scale), SecurityScorecard (0-100 per factor), and Black Kite (technical grade). The Prismatic rating uses a 300-900 numeric scale with letter grade mapping that corresponds to industry expectations.

Ratings are evidence-based and fully traceable. Every point deduction is linked to a specific finding with remediation guidance. This transparency allows organizations to understand exactly why they received a particular grade and what actions would improve their score. The Trinity Gate verification ensures that no rating is issued without structural, logical, and formal consistency in the underlying evidence.

Endpoint

GET /api/v1/perimeter/rating

Returns the security rating for a specified domain. If a recent discovery scan exists (within the configured cache window), the rating is computed from cached data. Otherwise, a lightweight scan is triggered automatically.

Port: 4004 Content-Type: application/json

Authentication

Requires a valid API token with perimeter:read scope.

Authorization: Bearer <api_token>

Request

Query Parameters

ParameterTypeRequiredDefaultDescription
domainstringYes--Domain to rate (e.g., example.com)
include_breakdownbooleanNotrueInclude per-category score breakdown
include_findingsbooleanNofalseInclude individual findings that affect the score
industrystringNononeIndustry vertical for percentile calculation (e.g., finance, healthcare, technology)

Headers

HeaderRequiredDescription
AuthorizationYesBearer token with perimeter:read scope
AcceptNoDefaults to application/json

Example Request

GET /api/v1/perimeter/rating?domain=example.com&include_breakdown=true&industry=technology HTTP/1.1
Host: localhost:4004
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Response

Success Response (200 OK)

{
  "ok": true,
  "data": {
    "domain": "example.com",
    "rating": {
      "grade": "B",
      "score": 780,
      "label": "Good",
      "percentile": 72,
      "industry_percentile": 68,
      "trend": "improving",
      "trend_delta": +15,
      "last_updated": "2026-02-12T10:30:00.000Z"
    },
    "breakdown": {
      "network_security": {
        "score": 85,
        "weight": 0.25,
        "grade": "B+",
        "findings_count": 3,
        "factors": [
          "TLS configuration is strong on primary domains",
          "2 hosts running outdated TLS versions",
          "No open database ports detected"
        ]
      },
      "application_security": {
        "score": 72,
        "weight": 0.20,
        "grade": "B-",
        "findings_count": 5,
        "factors": [
          "Security headers present on main site",
          "Missing Content-Security-Policy on 3 subdomains",
          "Staging environment publicly accessible"
        ]
      },
      "dns_health": {
        "score": 90,
        "weight": 0.15,
        "grade": "A-",
        "findings_count": 1,
        "factors": [
          "DNSSEC enabled",
          "SPF, DKIM, DMARC properly configured",
          "CAA records present"
        ]
      },
      "email_security": {
        "score": 88,
        "weight": 0.15,
        "grade": "A-",
        "findings_count": 1,
        "factors": [
          "DMARC policy set to reject",
          "DKIM signing active",
          "MTA-STS enabled"
        ]
      },
      "certificate_management": {
        "score": 65,
        "weight": 0.15,
        "grade": "C+",
        "findings_count": 4,
        "factors": [
          "2 certificates expiring within 30 days",
          "1 certificate using RSA-2048 (ECDSA recommended)",
          "Wildcard certificate covers primary domains"
        ]
      },
      "vulnerability_exposure": {
        "score": 78,
        "weight": 0.10,
        "grade": "B",
        "findings_count": 2,
        "factors": [
          "No known critical CVEs on exposed services",
          "2 services running versions with medium-severity patches available"
        ]
      }
    },
    "grade_scale": {
      "A": { "min": 850, "max": 900, "label": "Excellent" },
      "B": { "min": 700, "max": 849, "label": "Good" },
      "C": { "min": 550, "max": 699, "label": "Fair" },
      "D": { "min": 400, "max": 549, "label": "Poor" },
      "F": { "min": 300, "max": 399, "label": "Critical" }
    },
    "scan_basis": {
      "scan_id": "scan_2026021210300001",
      "scan_date": "2026-02-12T10:30:00.000Z",
      "assets_evaluated": 23,
      "data_freshness": "fresh"
    }
  },
  "meta": {
    "request_id": "req_rating_001",
    "dispatched_to": "PrismaticPerimeter.security_rating/1",
    "execution_time_ms": 234
  }
}

Response Fields

FieldTypeDescription
data.rating.gradestringLetter grade: A, B, C, D, or F
data.rating.scoreintegerNumeric score from 300 to 900
data.rating.labelstringHuman-readable label (Excellent, Good, Fair, Poor, Critical)
data.rating.percentileintegerPercentile rank across all rated domains (0-100)
data.rating.industry_percentileintegerPercentile within the specified industry vertical
data.rating.trendstringScore trend: improving, stable, declining
data.rating.trend_deltaintegerScore change since last rating
data.breakdownobjectPer-category score breakdown (when include_breakdown=true)
data.breakdown.*.scoreintegerCategory score (0-100)
data.breakdown.*.weightnumberCategory weight in overall score calculation
data.breakdown.*.gradestringCategory letter grade with +/- modifier
data.scan_basisobjectInformation about the underlying discovery scan

Grade Scale

GradeScore RangeLabelDescription
A850-900ExcellentIndustry-leading security posture
B700-849GoodStrong security with minor improvement areas
C550-699FairAdequate security with notable gaps
D400-549PoorSignificant security concerns requiring attention
F300-399CriticalSevere security deficiencies requiring immediate action

Code Examples

curl

# Get security rating
curl -s -H "Authorization: Bearer $API_TOKEN" \
  "http://localhost:4004/api/v1/perimeter/rating?domain=example.com" | jq '.data.rating'

# Get rating with full breakdown
curl -s -H "Authorization: Bearer $API_TOKEN" \
  "http://localhost:4004/api/v1/perimeter/rating?domain=example.com&include_breakdown=true" | \
  jq '.data.breakdown | to_entries[] | {category: .key, score: .value.score, grade: .value.grade}'

# Compare against industry
curl -s -H "Authorization: Bearer $API_TOKEN" \
  "http://localhost:4004/api/v1/perimeter/rating?domain=example.com&industry=technology" | \
  jq '{grade: .data.rating.grade, score: .data.rating.score, industry_percentile: .data.rating.industry_percentile}'

Elixir

# Direct function call
{:ok, rating} = PrismaticPerimeter.security_rating("example.com")

IO.puts("Grade: #{rating.grade} (#{rating.score}/900)")
IO.puts("Percentile: #{rating.percentile}th")

# With industry context
{:ok, rating} = PrismaticPerimeter.security_rating("example.com", industry: :technology)

# Check for poor ratings
if rating.score < 550 do
  Logger.error("Domain #{rating.domain} has a poor security rating: #{rating.grade}")
end

Python

import requests

headers = {"Authorization": f"Bearer {api_token}"}
params = {
    "domain": "example.com",
    "include_breakdown": True,
    "industry": "technology"
}

response = requests.get(
    "http://localhost:4004/api/v1/perimeter/rating",
    headers=headers,
    params=params
)

data = response.json()["data"]
rating = data["rating"]

print(f"Security Rating: {rating['grade']} ({rating['score']}/900)")
print(f"Industry Percentile: {rating['industry_percentile']}th")
print(f"Trend: {rating['trend']} ({rating['trend_delta']:+d})")

if "breakdown" in data:
    print("\nCategory Breakdown:")
    for category, details in data["breakdown"].items():
        print(f"  {category}: {details['grade']} ({details['score']}/100)")

Error Responses

Status CodeError CodeDescription
400invalid_domainDomain format is invalid
401unauthorizedMissing or invalid authentication token
403insufficient_scopeToken lacks perimeter:read scope
404no_scan_dataNo discovery data available for this domain (run a scan first)
422invalid_industryUnrecognized industry vertical
429rate_limitedRating request rate limit exceeded

Rate Limits

Limit TypeValueWindow
Per token60 requests1 minute
Per domain30 requests1 hour
Burst5 requests1 second

Ratings are computed from cached discovery data and are computationally lightweight. The per-domain limit prevents excessive re-rating of the same domain.

Methodology

The rating algorithm is transparent and reproducible. The overall score is a weighted sum of category scores, where each category evaluates specific security controls:

  1. Network Security (25%) -- TLS configuration, open ports, firewall effectiveness, protocol versions
  2. Application Security (20%) -- Security headers, exposed endpoints, staging/dev environments, WAF presence
  3. DNS Health (15%) -- DNSSEC, CAA records, zone configuration, dangling records
  4. Email Security (15%) -- SPF, DKIM, DMARC, MTA-STS, DANE
  5. Certificate Management (15%) -- Expiry dates, key strength, chain completeness, revocation status
  6. Vulnerability Exposure (10%) -- Known CVEs on exposed services, patch currency, end-of-life software

Every finding includes a severity classification (critical, high, medium, low, informational) and specific remediation guidance. The Quality DNA system tracks rating methodology changes across platform versions to ensure scoring consistency.


Connect & Contribute

Created by Tomáš Korcak (korczis) | Open Source under GHL