> ## Documentation Index
> Fetch the complete documentation index at: https://memproof.kyberon.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Risk Engine

> How Memproof scores memory operations across five weighted risk factors

# Risk Engine

The Risk Engine produces a numerical score (0.0 to 1.0) and a categorical risk level for every memory operation. This assessment is computed **before** the [Policy Engine](/concepts/policy-engine) runs, so policy rules can branch on `risk_score` and `risk_level`.

The current scorer is `memproof-baseline-v1`.

## Risk Factors

Each operation is evaluated across up to five factors. Every factor produces a `contribution` value between 0.0 and 1.0.

<Steps>
  <Step title="Operation Type">
    Different operation types carry different inherent risk. Read operations are low-risk; destructive operations are higher.

    | Operation  | Contribution |
    | ---------- | ------------ |
    | `get`      | 0.05         |
    | `search`   | 0.05         |
    | `remember` | 0.30         |
    | `update`   | 0.40         |
    | `forget`   | 0.50         |
  </Step>

  <Step title="PII Detection">
    Content is scanned against regex patterns for personally identifiable information. If PII is detected, a factor with contribution **0.60** is added.

    Detected patterns include: Social Security numbers, email addresses, credit card numbers, and phone numbers.
  </Step>

  <Step title="Secrets Detection">
    Content is scanned for embedded credentials and secrets. If a secret is detected, a factor with contribution **0.70** is added.

    Detected patterns include: API key assignments, bearer tokens, and keys matching the `sk-` prefix pattern.
  </Step>

  <Step title="Source Trust">
    The `context.source` field is compared against a set of trusted sources: `langgraph`, `openai_sessions`, and `mcp`.

    | Source                     | Contribution |
    | -------------------------- | ------------ |
    | Trusted (known adapter)    | 0.05         |
    | Untrusted (custom/unknown) | 0.40         |
  </Step>

  <Step title="Scope Anomaly">
    If the `tenant_id` or `project_id` is missing from the operation scope, a factor with contribution **0.70** is added. This flags operations that lack proper organizational context.
  </Step>
</Steps>

## Scoring Formula

The final score is computed in two steps:

**Step 1: Weighted average**

```
weighted_avg = sum(factor.contribution for each factor) / count(factors)
```

**Step 2: Floor boost from maximum factor**

```
final_score = max(weighted_avg, max_individual_contribution * 0.8)
```

The floor boost ensures that a single high-risk factor (like a detected secret at 0.70) cannot be diluted below 80% of its contribution by low-risk factors. The final score is clamped to a maximum of 1.0.

<Note>
  The floor boost is a deliberate design choice. A memory operation that contains an API key should never score "low risk" just because all other factors are clean.
</Note>

### Worked Example

Consider a `remember` operation from a trusted source (`langgraph`) that contains an email address:

| Factor                     | Contribution |
| -------------------------- | ------------ |
| operation\_type (remember) | 0.30         |
| content\_pii (email)       | 0.60         |
| source\_trust (trusted)    | 0.05         |

```
weighted_avg = (0.30 + 0.60 + 0.05) / 3 = 0.3167
max_individual = 0.60
floor_boost = 0.60 * 0.8 = 0.48
final_score = max(0.3167, 0.48) = 0.48
```

Result: **score = 0.48**, **level = medium**.

## Risk Levels

The score maps to one of four risk levels using configurable thresholds:

| Level      | Score Range  | Default Threshold    |
| ---------- | ------------ | -------------------- |
| `low`      | 0.00 -- 0.30 | `low_max: 0.30`      |
| `medium`   | 0.31 -- 0.60 | `medium_max: 0.60`   |
| `high`     | 0.61 -- 0.80 | `high_max: 0.80`     |
| `critical` | 0.81 -- 1.00 | `critical_max: 1.00` |

Thresholds can be customized in the policy YAML under `risk_thresholds`:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
risk_thresholds:
  low_max: 0.25
  medium_max: 0.50
  high_max: 0.75
  critical_max: 1.00
```

## Content Flags

In addition to the scored risk assessment, the Risk Engine produces boolean content flags that are passed to the [Policy Engine](/concepts/policy-engine) as condition fields:

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
flags = risk_engine.assess_content_flags(content)
# {"contains_pii": True, "contains_secret": False}
```

These map directly to the `content.contains_pii` and `content.contains_secret` fields available in policy rule conditions.

## How Risk Feeds Into Policy

The `RiskAssessment` and content flags are passed to the Policy Engine as part of the evaluation context. Policy rules can use any combination of risk data:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
# Block critical-risk operations
- id: block-critical
  priority: 10
  when:
    - field: risk_level
      operator: eq
      value: critical
  action: deny
  reason_codes: [CRITICAL_RISK]

# Require approval for high-risk writes
- id: approve-high-risk-writes
  priority: 20
  match: all
  when:
    - field: risk_score
      operator: gte
      value: 0.6
    - field: operation_type
      operator: in
      value: [remember, update]
  action: require_approval
  reason_codes: [HIGH_RISK_WRITE]
```

## RiskAssessment Model

Every operation response includes the full risk assessment:

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
result = await mp.remember(content="...", scope={...}, context={...})

assessment = result.risk_assessment
assessment.score    # 0.48
assessment.level    # RiskLevel.medium
assessment.scorer   # "memproof-baseline-v1"
assessment.factors  # [RiskFactor(name="operation_type", contribution=0.3, ...), ...]
```

Each `RiskFactor` in the `factors` list includes:

| Field          | Type           | Description                                               |
| -------------- | -------------- | --------------------------------------------------------- |
| `name`         | string         | Factor identifier (e.g., `operation_type`, `content_pii`) |
| `contribution` | float          | Score contribution, 0.0 to 1.0                            |
| `description`  | string         | Human-readable explanation                                |
| `evidence`     | string or null | Specific pattern matched (e.g., "Email address")          |

<Tip>
  Use the `factors` list in logging and dashboards to understand exactly why an operation scored the way it did.
</Tip>
