| name | implementing-api-security-posture-management |
| description | Implements API Security Posture Management (API-SPM) to continuously discover, classify, and risk-score APIs -- including internal, external, partner, and shadow endpoints -- while aggregating findings from DAST, SAST, SCA, and runtime monitoring into a unified risk view. Use when building continuous API inventory and risk-scoring, detecting configuration drift or policy violations, or unifying API risk visibility across an organization. |
| domain | cybersecurity |
| subdomain | api-security |
| tags | ["api-security","aspm","api-posture-management","api-discovery","risk-scoring","api-governance","continuous-monitoring","api-inventory"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
| nist_csf | ["PR.PS-01","ID.RA-01","PR.DS-10","DE.CM-01"] |
| mitre_attack | ["T1190","T1059.007","T1552.001"] |
Implementing API Security Posture Management
Overview
API Security Posture Management (API-SPM) provides continuous visibility into an organization's API attack surface by automatically discovering, classifying, and risk-scoring all APIs including internal, external, partner, and shadow endpoints. Unlike point-in-time testing tools, API-SPM operates continuously to detect configuration drift, policy violations, missing security controls, sensitive data exposure, and compliance gaps. It aggregates findings from DAST, SAST, SCA, and runtime monitoring tools to provide a unified view of API risk posture across the organization.
When to Use
- When deploying or configuring implementing api security posture management capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
Prerequisites
- API gateway with traffic logging (Kong, AWS API Gateway, Apigee, Envoy)
- OpenAPI specifications for documented APIs
- SIEM or log aggregation platform (Splunk, Elastic)
- CI/CD pipeline access for shift-left integration
- Cloud provider APIs for infrastructure discovery
- Python 3.8+ for custom posture assessment tooling
Core Components
1. API Discovery and Inventory
"""API Security Posture Management Engine
Continuously discovers, classifies, and risk-scores APIs
to maintain a comprehensive security posture inventory.
"""
import json
import re
import hashlib
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Set
from dataclasses import dataclass, field
from enum import Enum
class APIClassification(Enum):
EXTERNAL = "external"
INTERNAL =
PARTNER =
SHADOW =
DEPRECATED =
():
CRITICAL =
HIGH =
MEDIUM =
LOW =
INFO =
:
name:
present:
required:
severity: RiskLevel
details: =
:
api_id:
method:
path:
service_name:
classification: APIClassification
owner: [] =
version: [] =
first_discovered: =
last_seen: =
documented: =
security_controls: [SecurityControl] = field(default_factory=)
risk_score: =
sensitive_data_types: [] = field(default_factory=)
compliance_tags: [] = field(default_factory=)
traffic_volume_daily: =
:
SENSITIVE_PATTERNS = {
: re.(),
: re.(),
: re.(),
: re.(),
: re.(),
: re.(),
}
():
.inventory: [, APIEndpoint] = {}
.policy_rules: [] = []
() -> :
raw =
hashlib.sha256(raw.encode()).hexdigest()[:]
() -> APIEndpoint:
api_id = .generate_api_id(method, path, service_name)
now = datetime.now().isoformat()
api_id .inventory:
endpoint = .inventory[api_id]
endpoint.last_seen = now
endpoint
endpoint = APIEndpoint(
api_id=api_id,
method=method,
path=path,
service_name=service_name,
classification=classification,
owner=owner,
first_discovered=now,
last_seen=now,
documented=documented
)
.inventory[api_id] = endpoint
endpoint
() -> [SecurityControl]:
controls = []
has_auth = (h traffic_sample.get(, {})
h [, , ])
controls.append(SecurityControl(
name=,
present=has_auth,
required=,
severity=RiskLevel.CRITICAL,
details= has_auth
))
is_https = traffic_sample.get(, ).lower() ==
controls.append(SecurityControl(
name=,
present=is_https,
required=,
severity=RiskLevel.CRITICAL,
details= is_https
))
has_rate_limit = (h.startswith() h ==
h traffic_sample.get(, {}).keys())
controls.append(SecurityControl(
name=,
present=has_rate_limit,
required=,
severity=RiskLevel.HIGH,
details= has_rate_limit
))
cors_origin = traffic_sample.get(, {}).get(, )
has_strict_cors = cors_origin cors_origin !=
controls.append(SecurityControl(
name=,
present=has_strict_cors,
required=endpoint.classification == APIClassification.EXTERNAL,
severity=RiskLevel.HIGH cors_origin == RiskLevel.MEDIUM,
details= cors_origin
))
sec_headers = traffic_sample.get(, {})
required_headers = {
: ,
: ,
: ,
: ,
}
missing = [h h required_headers h sec_headers]
controls.append(SecurityControl(
name=,
present=(missing) == ,
required=,
severity=RiskLevel.MEDIUM,
details= missing
))
has_validation = traffic_sample.get(, )
controls.append(SecurityControl(
name=,
present=has_validation,
required=,
severity=RiskLevel.HIGH,
details= has_validation
))
endpoint.security_controls = controls
controls
() -> :
score =
max_score =
control endpoint.security_controls:
weight = control.severity.value *
max_score += weight
control.present control.required:
score += weight
classification_weights = {
APIClassification.EXTERNAL: ,
APIClassification.PARTNER: ,
APIClassification.SHADOW: ,
APIClassification.DEPRECATED: ,
APIClassification.INTERNAL: ,
}
multiplier = classification_weights.get(endpoint.classification, )
endpoint.documented:
score +=
score += (endpoint.sensitive_data_types) *
max_score > :
normalized = (, (score / max_score) * * multiplier)
:
normalized =
endpoint.risk_score = (normalized, )
endpoint.risk_score
() -> :
total = (.inventory)
total == :
{: }
risk_distribution = {level.name: level RiskLevel}
classification_counts = {c.value: c APIClassification}
undocumented =
missing_auth =
missing_tls =
endpoint .inventory.values():
.calculate_risk_score(endpoint)
endpoint.risk_score >= :
risk_distribution[] +=
endpoint.risk_score >= :
risk_distribution[] +=
endpoint.risk_score >= :
risk_distribution[] +=
:
risk_distribution[] +=
classification_counts[endpoint.classification.value] +=
endpoint.documented:
undocumented +=
control endpoint.security_controls:
control.name == control.present:
missing_auth +=
control.name == control.present:
missing_tls +=
avg_risk = (e.risk_score e .inventory.values()) / total
{
: datetime.now().isoformat(),
: total,
: (avg_risk, ),
: risk_distribution,
: classification_counts,
: undocumented,
: missing_auth,
: missing_tls,
: (
[{: e.api_id, : e.method, : e.path,
: e.service_name, : e.risk_score,
: e.classification.value}
e .inventory.values()],
key= x: x[],
reverse=
)[:]
}