Skip to main content

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:

NamespaceBase ScoreRationale
admin50Administrative operations carry inherent risk
exec45Code execution capabilities
system40System-level operations
database35Data storage operations
filesystem30File system access
network25Network operations
data25Data processing
api20API interactions
tools15General utility tools
default10Uncategorized 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

  1. Start with Defaults: Use default weights initially
  2. Analyze Patterns: Review scoring trends before adjusting
  3. Incremental Changes: Make small adjustments
  4. Test Thoroughly: Use dry-run to validate changes
  5. Document Changes: Record why weights were adjusted

Common Tuning Scenarios

ScenarioAdjustment
Too many approvals for readsLower verb_risk for read operations
Missing high-risk detectionsAdd custom resource patterns
Security-focused orgIncrease security weight to 0.45
Financial servicesIncrease financial weight to 0.25
After-hours ops commonReduce after_hours multiplier

Monitoring Score Accuracy

  1. Track False Positives: High scores for low-risk actions
  2. Track False Negatives: Low scores for risky actions
  3. Review Overrides: Actions approved despite high scores
  4. Audit Periodically: Monthly review of scoring accuracy

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