AI-Guided Cross-Chain Bridge Security · Smithkeem/SentinelBridge · February 21, 2026
SentinelBridge implements an AI-guided cross-chain bridge security system on Stacks. An off-chain AI agent assesses transfer risk in real-time, can pause the bridge, dynamically adjust limits, and block malicious addresses. The contract manages transfer requests with per-chain volume tracking and a multi-level incident response system.
The architecture separates three roles: Contract Owner (admin), AI Agent (risk assessment), and Security Guardians (emergency address blocking). Transfer requests go through risk scoring before approval.
initiate-transfer → AI calls submit-risk-assessment → status becomes APPROVED/REJECTED/FLAGGEDanalyze-incident-report takes threat vectors + metrics, triggers graduated response (NORMAL → WARNING → CRITICAL)| # | Severity | Title |
|---|---|---|
| 1 | CRITICAL | No actual token transfers — bridge is pure bookkeeping |
| 2 | CRITICAL | Transfer limit ratchets to zero permanently |
| 3 | HIGH | Daily volume limits never reset |
| 4 | HIGH | Risk assessment overwrites previous decisions |
| 5 | HIGH | Volume counted on initiation, never refunded on rejection |
| 6 | MEDIUM | tx-sender auth for AI agent bypassable |
| 7 | MEDIUM | Immutable contract owner — no transfer function |
| 8 | MEDIUM | Hardcoded limit recovery ignores configured values |
| 9 | LOW | No transfer execution function |
| 10 | LOW | Asymmetric guardian permissions |
| 11 | INFO | No events for administrative changes |
initiate-transfer never calls stx-transfer? or any token transfer function. The bridge records transfer requests but never locks, escrows, or moves any funds.
(define-public (initiate-transfer (amount uint) (target-chain (string-ascii 10)) (target-address (string-ascii 42)))
(let (...)
;; Creates a record... but never transfers tokens
(map-set transfer-requests request-id { ... })
(ok request-id)))
Impact: The entire bridge is non-functional. An "approved" transfer has zero on-chain effect — no funds are secured, locked, or transferred. Users can initiate transfers for amounts they don't hold.
Fix: Add (try! (stx-transfer? amount tx-sender (as-contract tx-sender))) to lock funds on initiation, and an execute-transfer function to release them on approval.
In analyze-incident-report, warning-level incidents divide the global transfer limit by 4:
(var-set global-transfer-limit (/ (var-get global-transfer-limit) u4))
Due to Clarity's integer floor division, repeated warnings cause irreversible decay:
u10000 → u2500 → u625 → u156 → u39 → u9 → u2 → u0
Once at u0, the limit check (<= amount u0) blocks ALL transfers. Recovery only triggers when threat-score < 10, restoring to hardcoded u10000 — but there's no admin override to manually set the limit.
Impact: A series of warning-level incidents (which are expected in normal bridge operation) permanently disables all transfers. An attacker can trigger this by submitting borderline threat reports.
Fix: Add an admin function to set limits directly. Use subtraction instead of division for graduated reduction, or set a minimum floor (e.g., (max (/ limit u4) u100)).
current-volume on each chain monotonically increases and never resets:
(map-set supported-chains target-chain
(merge chain-config { current-volume: (+ (get current-volume chain-config) amount) }))
The only way to reset is for the owner to call configure-chain manually, which also wipes the chain's risk score. The "daily limit" is effectively a lifetime limit.
Impact: Every chain eventually hits its limit and becomes permanently unusable. The bridge has a finite total capacity equal to the configured limit per chain.
Fix: Track the last reset block, and automatically reset volume when sufficient blocks have passed (e.g., ~144 blocks ≈ 1 day on Stacks).
submit-risk-assessment never checks the current status of the transfer request:
(let ((request (unwrap! (map-get? transfer-requests request-id) ERR-INVALID-REQUEST)))
(asserts! (is-ai-agent) ERR-NOT-AUTHORIZED)
;; No check: (asserts! (is-eq (get status request) STATUS-PENDING) ...)
(map-set transfer-requests request-id (merge request { status: new-status, risk-score: risk-score })))
Impact: A compromised or buggy AI agent can flip already-approved transfers to rejected (griefing) or flip rejected transfers to approved (bypassing security). The finality of risk decisions is broken.
When initiate-transfer is called, the transfer amount is immediately added to the chain's current-volume. If the AI agent later rejects the transfer, the volume is never decremented.
Impact: Grief attack — an attacker spams transfer requests on a target chain. All get rejected, but the chain's volume limit is exhausted. Combined with Finding #3 (no volume reset), this permanently disables the chain.
Fix: Decrement volume in submit-risk-assessment when status is REJECTED, or only count volume for approved transfers.
(define-private (is-ai-agent)
(is-eq tx-sender (var-get authorized-ai-agent)))
Uses tx-sender (the original transaction sender) instead of contract-caller (the immediate caller). If the AI agent is an EOA, any contract it calls could use this contract as an intermediary. Should use contract-caller for tighter access control.
CONTRACT-OWNER is defined as (define-constant CONTRACT-OWNER tx-sender) — set permanently at deploy time. There's no ownership transfer function. If the deployer key is compromised or lost, the contract becomes unmanageable: no new chains, no guardian changes, no AI agent rotation.
(if (< current-score u10)
(var-set global-transfer-limit u10000)
true)
Recovery always resets to u10000 regardless of what the operational limit should be. If the bridge was configured for higher throughput (e.g., u1000000), recovery throttles it to 1% of capacity.
There's no execute-transfer or complete-transfer function. Even after AI approval, nothing happens on-chain. The contract is an incomplete risk-assessment layer with no bridge mechanics underneath.
Guardians are described as an "emergency" role but can only block/unblock addresses. They cannot pause the bridge, adjust limits, configure chains, or submit risk assessments. For incident response, their powers are surprisingly limited.
Guardian additions/removals, AI agent changes, and chain configuration changes emit no print events. The contract is designed for off-chain monitoring but provides no visibility into admin actions.
SentinelBridge is architecturally interesting — the AI-guided risk assessment pattern is a novel approach to bridge security. However, the contract is fundamentally incomplete. The most critical issue is that no actual token transfers occur; it's a risk assessment framework without a bridge underneath. Beyond that, the transfer limit mechanism has a fatal ratchet-to-zero bug, volume tracking is broken (no reset), and risk assessments lack finality.
Not safe for production use. Requires fundamental redesign of token handling, limit management, and volume tracking before deployment.