Dev.to Security πŸ” Cybersecurity πŸ‘ 0 πŸ“– 7 min read

BIGF v2.4 Lab: Enforcing Deterministic AI Agent Boundaries with OPA, Rego & RFC 8785

Welcome to the **VITI Labs* hands-on guide.* System prompts are not security boundaries. If an autonomous AI agent is allowed to delegate tasks to sub-agents (Agent-to-Agent / A2A) or execute financial and infrastructur

Welcome to the **VITI Labs* hands-on guide.*

System prompts are not security boundaries. If an autonomous AI agent is allowed to delegate tasks to sub-agents (Agent-to-Agent / A2A) or execute financial and infrastructure mutations, governance must happen outside the LLM at a deterministic runtime gate.

In this lab, you will build and test a complete Business Impact Governance Framework (BIGF v2.4) policy gate using Open Policy Agent (OPA), Rego, and RFC 8785 JSON Canonicalization (JCS).

Architecture: How the Gate Works

Every A2A delegation or actuation request passes through three deterministic stages before execution:

  1. Ingress Sanitization (BIGF-DCS): Raw JSON floats (IEEE 754) are rejected immediately (422 Unprocessable). All currency and threshold values must be encoded as 10-4 fixed-point strings ("2450.5000").
  2. Cryptographic Lineage (RFC 8785 JCS + SHA-256): The child contract must carry the exact SHA-256 hash of its canonicalized parent contract (parent_jcs_sha256) to prevent privilege injection or chain tampering.
  3. Monotonic Narrowing (B Γ— S Γ— T): A child agent can never expand its parent's authority:
    • B-Axis (Business Impact): child.max_exposure_fp4 <= parent.max_exposure_fp4 and currencies must match.
    • S-Axis (Situational State / BIII): child.min_biii_fp4 >= parent.min_biii_fp4 (integrity requirements can only tighten), and live telemetry BIII must meet the threshold.
    • T-Axis (Time & Telemetry): child.max_ttl_sec <= parent.max_ttl_sec, and the contract must fall strictly within the parent's [iat, exp] window.

Step 1: Project Structure

Create a directory bigf-opa-lab with four files:

bigf-opa-lab/
β”œβ”€β”€ jcs_hash.py        # RFC 8785 canonicalizer & SHA-256 lineage generator
β”œβ”€β”€ bigf_gate.rego     # Deterministic BIGF v2.4 OPA policy
β”œβ”€β”€ bigf_gate_test.rego# Runnable OPA unit test suite (200 OK, 403 Halt, 422 Reject)
└── input_valid.json   # Sample A2A parent-to-child delegation payload

Step 2: RFC 8785 Canonicalizer (jcs_hash.py)

Before OPA evaluates a delegation chain, the orchestrator or ingress proxy canonicalizes the parent contract per RFC 8785 (sorted keys, zero insignificant whitespace, UTF-8) and verifies parent_jcs_sha256.

import hashlib
import json

def canonicalize_jcs(obj: dict) -> bytes:
    """RFC 8785 deterministic JSON canonicalization (UTF-8)."""
    return json.dumps(
        obj,
        sort_keys=True,
        separators=(",", ":"),
        ensure_ascii=False
    ).encode("utf-8")

def compute_jcs_sha256(obj: dict) -> str:
    """Computes the deterministic SHA-256 lineage hash."""
    return hashlib.sha256(canonicalize_jcs(obj)).hexdigest()

if __name__ == "__main__":
    parent_contract = {
        "bigf_version": "2.4.0",
        "contract_id": "a2a-parent-9f8e7d6c",
        "delegation_depth": 1,
        "exp": 1794509100,
        "iat": 1794508800,
        "invariants": {
            "b_axis": {
                "currency": "EUR",
                "max_exposure_fp4": "10000.0000",
                "regulatory_anchor": ["DORA", "NIS2"]
            },
            "s_axis": {
                "allowed_transitions": ["INVOICE_VERIFY", "SETTLEMENT_EXECUTE"],
                "min_biii_fp4": "0.8000"
            },
            "t_axis": {
                "max_ttl_sec": 300
            }
        },
        "iss": "ed25519:3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29",
        "parent_jcs_sha256": None,
        "sub": "agent:procurement-eu-01"
    }
    print("parent_jcs_sha256:", compute_jcs_sha256(parent_contract))

Step 3: The Deterministic Rego Gate (bigf_gate.rego)

Save this policy as bigf_gate.rego. Notice how Rego enforces fail-closed physics: if any violation fires, allow defaults to false and the gate emits a structured 403 HARD HALT or 422 REJECTED decision record.

package bigf.v2_4.gate

import rego.v1

# Fail-closed default
default allow := false

# 1. BIGF-DCS Ingress Guard: Reject any raw JSON floating-point numbers
dcs_float_violations contains msg if {
    some path, val in walk(input)
    is_number(val)
    # In JSON/Rego, non-integers (e.g., 2450.5) fail exact integer division check
    round(val) != val
    msg := sprintf("422 BIGF-DCS Type Violation: IEEE 754 float detected at %v", [path])
}

# Fixed-point string parser (10^-4 scaling via to_number on validated strings)
parse_fp4(str) := num if {
    is_string(str)
    regex.match(`^\d+\.\d{4}$`, str)
    num := to_number(str)
}

# 2. Cryptographic Lineage & Depth Checks
violations contains "CRYPTO_AXIS: parent_jcs_sha256 mismatch" if {
    input.child.parent_jcs_sha256 != input.computed_parent_jcs_sha256
}

violations contains "CRYPTO_AXIS: Invalid delegation depth increment" if {
    input.child.delegation_depth != input.parent.delegation_depth + 1
}

# 3. B-Axis (Business Impact Monotonic Narrowing)
violations contains "B_AXIS: Currency mismatch between parent and child" if {
    input.child.invariants.b_axis.currency != input.parent.invariants.b_axis.currency
}

violations contains "B_AXIS: Child exposure exceeds parent ceiling" if {
    child_exp := parse_fp4(input.child.invariants.b_axis.max_exposure_fp4)
    parent_exp := parse_fp4(input.parent.invariants.b_axis.max_exposure_fp4)
    child_exp > parent_exp
}

violations contains "B_AXIS: Requested action amount exceeds child ceiling" if {
    req_amt := parse_fp4(input.request.amount_fp4)
    child_exp := parse_fp4(input.child.invariants.b_axis.max_exposure_fp4)
    req_amt > child_exp
}

# 4. S-Axis (Situational Integrity & Transition Subset)
violations contains "S_AXIS: Child weakened min_biii_fp4 requirement" if {
    child_biii := parse_fp4(input.child.invariants.s_axis.min_biii_fp4)
    parent_biii := parse_fp4(input.parent.invariants.s_axis.min_biii_fp4)
    child_biii < parent_biii
}

violations contains "S_AXIS: Live telemetry BIII below required threshold" if {
    live_biii := parse_fp4(input.telemetry.live_biii_fp4)
    req_biii := parse_fp4(input.child.invariants.s_axis.min_biii_fp4)
    live_biii < req_biii
}

violations contains "S_AXIS: Requested transition not permitted by child contract" if {
    not input.request.transition in input.child.invariants.s_axis.allowed_transitions
}

violations contains "S_AXIS: Child transitions exceed parent scope" if {
    some t in input.child.invariants.s_axis.allowed_transitions
    not t in input.parent.invariants.s_axis.allowed_transitions
}

# 5. T-Axis (Time Window & TTL Bounds)
violations contains "T_AXIS: Child TTL exceeds parent max_ttl_sec" if {
    input.child.invariants.t_axis.max_ttl_sec > input.parent.invariants.t_axis.max_ttl_sec
}

violations contains "T_AXIS: Child validity window escapes parent [iat, exp]" if {
    input.child.iat < input.parent.iat
}

violations contains "T_AXIS: Child expiration exceeds parent expiration" if {
    input.child.exp > input.parent.exp
}

violations contains "T_AXIS: Contract expired at evaluation timestamp" if {
    input.telemetry.now_utc > input.child.exp
}

# Final Deterministic Gate Decision
allow if {
    count(dcs_float_violations) == 0
    count(violations) == 0
}

# Canonical Decision Record (CDR) Output
decision := {
    "status": "422 UNPROCESSABLE",
    "state": "INGRESS_SCHEMA_VIOLATION",
    "privileges_propagated": 0,
    "violations": dcs_float_violations,
} if {
    count(dcs_float_violations) > 0
} else := {
    "status": "403 HARD HALT",
    "state": "UNVERIFIED_CRITICAL_STATE",
    "privileges_propagated": 0,
    "violations": violations,
} if {
    count(violations) > 0
} else := {
    "status": "200 OK",
    "state": "VERIFIED_EXECUTION",
    "approved_amount_fp4": input.request.amount_fp4,
    "biii_fp4": input.telemetry.live_biii_fp4,
    "lineage_sha256": input.child.parent_jcs_sha256,
}

Step 4: Runnable OPA Unit Tests (bigf_gate_test.rego)

Save this test suite alongside bigf_gate.rego to verify all three enforcement outcomes (200 OK, 403 HARD HALT, and 422 UNPROCESSABLE):

package bigf.v2_4.gate_test

import data.bigf.v2_4.gate
import rego.v1

base_input := {
    "computed_parent_jcs_sha256": "7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a",
    "parent": {
        "delegation_depth": 1,
        "iat": 1794508800,
        "exp": 1794509100,
        "invariants": {
            "b_axis": {"currency": "EUR", "max_exposure_fp4": "10000.0000"},
            "s_axis": {
                "allowed_transitions": ["INVOICE_VERIFY", "SETTLEMENT_EXECUTE"],
                "min_biii_fp4": "0.8000"
            },
            "t_axis": {"max_ttl_sec": 300}
        }
    },
    "child": {
        "delegation_depth": 2,
        "iat": 1794508810,
        "exp": 1794508920,
        "parent_jcs_sha256": "7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a",
        "invariants": {
            "b_axis": {"currency": "EUR", "max_exposure_fp4": "2450.5000"},
            "s_axis": {
                "allowed_transitions": ["SETTLEMENT_EXECUTE"],
                "min_biii_fp4": "0.8500"
            },
            "t_axis": {"max_ttl_sec": 110}
        }
    },
    "request": {
        "transition": "SETTLEMENT_EXECUTE",
        "amount_fp4": "2450.5000"
    },
    "telemetry": {
        "live_biii_fp4": "0.9100",
        "now_utc": 1794508850
    }
}

# Test 1: Valid attenuated delegation -> 200 OK
test_valid_monotonic_delegation if {
    gate.allow with input as base_input
    gate.decision.status == "200 OK" with input as base_input
}

# Test 2: Privilege escalation (child tries to raise exposure above parent) -> 403 HARD HALT
test_reject_exposure_escalation if {
    bad := json.patch(base_input, [{"op": "replace", "path": "/child/invariants/b_axis/max_exposure_fp4", "value": "15000.0000"}])
    not gate.allow with input as bad
    gate.decision.status == "403 HARD HALT" with input as bad
}

# Test 3: Telemetry degradation (live BIII drops below 0.8500) -> 403 HARD HALT
test_reject_low_biii if {
    degraded := json.patch(base_input, [{"op": "replace", "path": "/telemetry/live_biii_fp4", "value": "0.7900"}])
    not gate.allow with input as degraded
    gate.decision.status == "403 HARD HALT" with input as degraded
}

# Test 4: IEEE 754 float injected into payload -> 422 UNPROCESSABLE
test_reject_ieee754_float if {
    float_payload := json.patch(base_input, [{"op": "replace", "path": "/request/amount_fp4", "value": 2450.5}])
    not gate.allow with input as float_payload
    gate.decision.status == "422 UNPROCESSABLE" with input as float_payload
}

Step 5: Run It in 10 Seconds

Install the OPA binary (or run via Docker) and execute the test suite:

opa test . -v

Expected output:

bigf_gate_test.rego:
data.bigf.v2_4.gate_test.test_valid_monotonic_delegation: PASS (1.2ms)
data.bigf.v2_4.gate_test.test_reject_exposure_escalation: PASS (0.8ms)
data.bigf.v2_4.gate_test.test_reject_low_biii: PASS (0.7ms)
data.bigf.v2_4.gate_test.test_reject_ieee754_float: PASS (0.9ms)
--------------------------------------------------------------------------------
PASS: 4/4

Four deterministic checks executed in under 4 millisecondsβ€”zero CAB meetings, zero floating-point drift, and cryptographic lineage enforced before a single byte hits production.

Explore the full BIGF v2.4 specification & open-access whitepapers:

Just google it: BIG framework Erkki Laine (available on Zenodo & ORCID under CC BY-NC 4.0) ✌️

πŸ“° Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.