Risk Score Calculation
Overview
This document provides a detailed technical explanation of how Ascend calculates risk scores for AI agent actions and MCP tool calls. Understanding the calculation methodology helps security teams tune risk thresholds and customize scoring for their organization's specific needs.
Key Capabilities
- Transparent Scoring: Full visibility into how scores are calculated
- Reproducible Results: Consistent scores for identical inputs
- Configurable Weights: Adjust category and factor weights
- Audit Trail: Complete record of scoring decisions
- Real-Time Performance: Sub-200ms calculation times
Calculation Pipeline
Overall Flow
┌─────────────────────────────────────────────────────────────────────────────┐
│ RISK SCORE CALCULATION PIPELINE │
└─────────────────────────────────────────────────────────────────────────────┘
INPUT CALCULATION OUTPUT
───── ─────────── ──────
┌─────────────┐ ┌─────────────────────────────────┐ ┌─────────────┐
│ Action │ │ │ │ Total Score │
│ - Type │ │ 1. Base Score Calculation │ │ (0-100) │
│ - Resource │────>│ - Namespace risk │────>│ │
│ - Namespace │ │ - Verb risk │ │ Risk Level │
│ │ │ - Resource risk │ │ (5 levels) │
└─────────────┘ │ │ │ │
│ 2. Category Scoring │ │ Category │
┌─────────────┐ │ - Security (35%) │ │ Breakdown │
│ Context │ │ - Data (30%) │ │ │
│ - User │────>│ - Compliance (20%) │────>│ Risk │
│ - Env │ │ - Financial (15%) │ │ Factors │
│ - Time │ │ │ │ │
│ - IP │ │ 3. Context Multipliers │ │ Approval │
└─────────────┘ │ - Environment │ │ Level │
│ - User role │ │ │
┌─────────────┐ │ - Access source │ │ Recommend- │
│ Policies │────>│ - Time of day │ │ ations │
│ (matched) │ │ │ │ │
└─────────────┘ │ 4. Policy Adjustments │ └─────────────┘
│ - Matched policy impact │
│ │
│ 5. Final Score │
│ - Weighted sum │
│ - Capped at 0-100 │
└─────────────────────────────────┘
Step 1: Base Score Calculation
Namespace Risk Scores
Base risk scores assigned by namespace:
| Namespace | Base Score | Rationale |
|---|---|---|
admin | 50 | Administrative operations carry inherent risk |
exec | 45 | Code execution capabilities |
system | 40 | System-level operations |
database | 35 | Data storage operations |
filesystem | 30 | File system access |
network | 25 | Network operations |
data | 25 | Data processing |
api | 20 | API interactions |
tools | 15 | General utility tools |
default | 10 | Uncategorized operations |
Verb Risk Scores
Risk scores based on operation type:
VERB_RISK_SCORES = {
# Critical operations (40 points)
"delete": 40,
"remove": 40,
"destroy": 40,
"drop": 40,
"truncate": 40,
"kill": 40,
"exec": 40,
"execute": 40,
"run": 40,
"eval": 40,
"sudo": 40,
# High-risk operations (25 points)
"write": 25,
"create": 25,
"modify": 25,
"update": 25,
"insert": 25,
"alter": 25,
"grant": 25,
"revoke": 25,
"chmod": 25,
"chown": 25,
# Medium-risk operations (15 points)
"copy": 15,
"move": 15,
"rename": 15,
"link": 15,
"mount": 15,
"unmount": 15,
# Low-risk operations (5 points)
"read": 5,
"list": 5,
"describe": 5,
"get": 5,
"query": 5,
"scan": 5,
"search": 5,
"count": 5,
"check": 5
}
Resource Risk Patterns
Resources are evaluated for sensitive patterns:
RESOURCE_RISK_PATTERNS = {
# Credentials and secrets (50 points)
r"credential|password|secret|api_key|token|certificate": 50,
r"\.pem$|\.key$|vault": 50,
# Personal/sensitive data (40 points)
r"pii|personal|ssn|social_security": 40,
r"credit_card|bank_account|financial": 40,
r"patient|medical|health|hipaa|phi": 40,
# Production systems (30 points)
r"^prod\.|production\.|prod-|production-": 30,
# Customer/user data (25 points)
r"customer|user|client|member": 25,
# Configuration (20 points)
r"config|setting|permission|role|policy": 20,
# Audit/compliance (15 points)
r"audit|compliance|log|regulatory": 15
}
def calculate_resource_risk(resource: str) -> int:
"""Calculate resource risk based on pattern matching."""
max_risk = 0
for pattern, risk in RESOURCE_RISK_PATTERNS.items():
if re.search(pattern, resource, re.IGNORECASE):
max_risk = max(max_risk, risk)
return max_risk
Base Score Formula
Base_Score = Namespace_Risk + Verb_Risk + Resource_Risk
Where:
- Namespace_Risk: 10-50 based on namespace
- Verb_Risk: 5-40 based on operation type
- Resource_Risk: 0-50 based on resource patterns
Maximum possible base score: 140 (capped at 100)
Step 2: Category Scoring
Each category evaluates specific risk indicators:
Security Category (Weight: 35%)
def calculate_security_score(action, context) -> int:
score = 0
# Admin/privilege operations
if "admin" in action.type.lower():
score += 30
if "privilege" in action.type.lower():
score += 25
if "access" in action.type.lower():
score += 20
# Credential indicators
if context.accesses_credentials:
score += 35
if context.modifies_permissions:
score += 30
# User context
if context.user_role in ["admin", "superuser"]:
score += 20
return min(100, score)
Data Category (Weight: 30%)
def calculate_data_score(action, context) -> int:
score = 0
# PII indicators
pii_indicators = ["pii", "personal", "customer", "sensitive", "private"]
if any(ind in action.resource.lower() for ind in pii_indicators):
score += 40
# Data classification
if context.data_classification == "confidential":
score += 35
elif context.data_classification == "internal":
score += 20
# Database operations
if context.namespace in ["database", "storage"]:
score += 15
return min(100, score)
Compliance Category (Weight: 20%)
def calculate_compliance_score(action, context) -> int:
score = 0
# Regulatory frameworks
compliance_indicators = ["audit", "compliance", "regulatory", "legal"]
if any(ind in action.resource.lower() for ind in compliance_indicators):
score += 30
# Specific frameworks
framework_indicators = ["sox", "hipaa", "gdpr", "pci", "iso"]
if any(ind in action.resource.lower() for ind in framework_indicators):
score += 35
# Production environment
if context.environment == "production":
score += 20
return min(100, score)
Financial Category (Weight: 15%)
def calculate_financial_score(action, context) -> int:
score = 0
# Financial indicators
if "billing" in action.type.lower():
score += 35
if "payment" in action.resource.lower():
score += 40
# Transaction indicators
financial_indicators = ["transaction", "purchase", "invoice", "accounting"]
if any(ind in action.resource.lower() for ind in financial_indicators):
score += 30
return min(100, score)
Weighted Category Calculation
Category_Score = (Security × 0.35) + (Data × 0.30) + (Compliance × 0.20) + (Financial × 0.15)
Step 3: Context Multipliers
Context factors amplify or reduce the base score:
Multiplier Values
CONTEXT_MULTIPLIERS = {
# Environment
"production": 1.5,
"staging": 1.2,
"development": 0.8,
"test": 0.6,
# User role
"admin_user": 1.4,
"service_account": 1.3,
"superuser": 1.5,
"standard_user": 1.0,
# Access source
"external_access": 2.0,
"vpn_access": 1.2,
"internal_access": 1.0,
# Time
"after_hours": 1.3,
"weekend": 1.2,
"business_hours": 1.0,
# Operation type
"bulk_operation": 1.6,
"batch_operation": 1.4,
"single_operation": 1.0
}
Multiplier Calculation
def calculate_context_multiplier(context) -> float:
multiplier = 1.0
# Environment
if context.environment in CONTEXT_MULTIPLIERS:
multiplier *= CONTEXT_MULTIPLIERS[context.environment]
# User role
if context.user_role in ["admin", "superuser"]:
multiplier *= CONTEXT_MULTIPLIERS["admin_user"]
elif context.is_service_account:
multiplier *= CONTEXT_MULTIPLIERS["service_account"]
# Access source
if is_external_ip(context.client_ip):
multiplier *= CONTEXT_MULTIPLIERS["external_access"]
elif is_vpn_ip(context.client_ip):
multiplier *= CONTEXT_MULTIPLIERS["vpn_access"]
# Time
if is_after_hours(context.timestamp):
multiplier *= CONTEXT_MULTIPLIERS["after_hours"]
elif is_weekend(context.timestamp):
multiplier *= CONTEXT_MULTIPLIERS["weekend"]
# Cap multiplier at 2.5
return min(2.5, multiplier)
Step 4: Policy Adjustments
Matched policies can adjust the score:
POLICY_ADJUSTMENTS = {
"DENY": +30, # If policy would deny, high risk
"ESCALATE": +20, # Escalation indicates elevated risk
"REQUIRE_APPROVAL": +10, # Approval needed indicates risk
"ALLOW": -5 # Explicit allow slightly reduces risk
}
def calculate_policy_adjustment(matched_policies) -> int:
adjustment = 0
for policy in matched_policies:
if policy.confidence > 0.7: # Only high-confidence matches
adjustment += POLICY_ADJUSTMENTS.get(policy.decision, 0)
# Cap adjustment at +30/-10
return max(-10, min(30, adjustment))
Step 5: Final Score Calculation
Complete Formula
Final_Score = min(100, max(0,
(Category_Score + Policy_Adjustment) × Context_Multiplier
))
Risk Level Determination
def determine_risk_level(total_score, category_scores) -> tuple:
"""Determine risk level, approval requirement, and approval level."""
# Check for critical scores in any category
if any(score >= 90 for score in category_scores.values()):
return "CRITICAL", True, 5
# Score-based levels
if total_score >= 90:
return "CRITICAL", True, 5
elif total_score >= 80:
return "HIGH", True, 4
elif total_score >= 70:
return "HIGH", True, 3
elif total_score >= 50:
return "MEDIUM", True, 2
elif total_score >= 25:
return "LOW", False, 1
else:
return "MINIMAL", False, 0
Calculation Example
Input
{
"action_type": "database_update",
"resource": "production.customer_pii",
"namespace": "database",
"context": {
"user_role": "analyst",
"environment": "production",
"client_ip": "192.168.1.100",
"timestamp": "2026-01-20T14:30:00Z"
}
}
Step-by-Step Calculation
1. BASE SCORE CALCULATION
───────────────────────
Namespace (database): 35
Verb (update): 25
Resource (production, customer_pii): 30 + 40 = 70 (capped at 50)
Base Score: 35 + 25 + 50 = 110 → 100 (capped)
2. CATEGORY SCORING
─────────────────
Security:
- No admin operation: +0
- No credential access: +0
- Standard user: +0
Security Score: 25 (base from namespace)
Data:
- "customer_pii" matches PII pattern: +40
- Database namespace: +15
Data Score: 55
Compliance:
- Production environment: +20
- No compliance keywords: +0
Compliance Score: 35
Financial:
- No financial indicators: +0
Financial Score: 15
Weighted Score: (25 × 0.35) + (55 × 0.30) + (35 × 0.20) + (15 × 0.15)
= 8.75 + 16.5 + 7.0 + 2.25
= 34.5
3. CONTEXT MULTIPLIERS
────────────────────
- Production environment: × 1.5
- Standard user role: × 1.0
- Internal IP: × 1.0
- Business hours: × 1.0
Combined Multiplier: 1.5
4. POLICY ADJUSTMENTS
───────────────────
- Matched "production-database-protection": REQUIRE_APPROVAL
- Confidence: 0.85 (high)
Policy Adjustment: +10
5. FINAL CALCULATION
──────────────────
Raw Score: (34.5 + 10) × 1.5 = 66.75
Final Score: 67 (rounded)
6. RESULT
───────
Total Score: 67
Risk Level: MEDIUM
Requires Approval: Yes
Approval Level: 2 (Manager)
Configuration
Customize Category Weights
from ascend import AscendClient
client = AscendClient(api_key="your-api-key")
# Update category weights
client.risk.update_weights(
security=0.40, # Increase security weight
data=0.30,
compliance=0.20,
financial=0.10 # Decrease financial weight
)
Add Custom Resource Patterns
from ascend import AscendClient
client = AscendClient(api_key="your-api-key")
# Add custom resource risk patterns
client.risk.add_resource_pattern(
pattern=r"proprietary|trade_secret|confidential_business",
risk_score=45,
description="Proprietary business information"
)
Modify Context Multipliers
from ascend import AscendClient
client = AscendClient(api_key="your-api-key")
# Update context multipliers
client.risk.update_multipliers({
"production": 1.6, # Increase prod multiplier
"external_access": 2.5, # Higher for external
"service_account": 1.5 # Higher for service accounts
})
Best Practices
Tuning Recommendations
- Start with Defaults: Use default weights initially
- Analyze Patterns: Review scoring trends before adjusting
- Incremental Changes: Make small adjustments
- Test Thoroughly: Use dry-run to validate changes
- Document Changes: Record why weights were adjusted
Common Tuning Scenarios
| Scenario | Adjustment |
|---|---|
| Too many approvals for reads | Lower verb_risk for read operations |
| Missing high-risk detections | Add custom resource patterns |
| Security-focused org | Increase security weight to 0.45 |
| Financial services | Increase financial weight to 0.25 |
| After-hours ops common | Reduce after_hours multiplier |
Monitoring Score Accuracy
- Track False Positives: High scores for low-risk actions
- Track False Negatives: Low scores for risky actions
- Review Overrides: Actions approved despite high scores
- Audit Periodically: Monthly review of scoring accuracy
Related
- Risk Scoring Overview - Scoring fundamentals
- Security Frameworks - Framework mapping
- Threshold Configuration - Configuring thresholds
- Policy Engine - How scores affect policies
Compliance
Risk calculation methodology supports compliance with:
- SOC 2 CC3.1: Risk assessment methodology
- PCI-DSS 12.2: Risk assessment process
- NIST 800-53 RA-3: Risk assessment
- ISO 27001 A.12.6: Technical vulnerability management
- HIPAA 164.308(a)(1): Risk analysis methodology