Picture this scenario.
You are one of four signers on a protocol treasury holding twelve million dollars in digital assets. It is 3:15 AM on a Tuesday. Your phone buzzes with a Safe notification:
Pending multisig transaction: 1 of 3 signatures confirmed.
You open the Safe web app on your phone, half-asleep. The destination is an unverified proxy contract ending in ...f9c2. The function selector is 0x8c5be1e5, followed by two kilobytes of hex-encoded calldata. The proposer is one of your co-signers who lives six time zones away.
Do you sign it?
Be honest. Most signers click "Approve" on their hardware wallet. They trust their peer. They assume someone else checked the calldata. They tell themselves they will review the transaction receipt in the morning.
That is how Web3 treasuries get drained.
Not because someone cracked elliptic-curve cryptography. Treasuries get drained because of human operational fatigue, time-zone drag, and blind signing.
Today, I built an open-source tool to solve this: The Safe & Treasury Sentinel.
It is a self-hostable, automated monitoring workflow built in n8n. It receives live Safe Infrastructure webhooks, runs a 15-minute scheduled state reconciliation, diffs your live wallet configuration against an approved baseline, and uses an AI agent to explain the calldata in plain English.
Most importantly: it does not touch a single private key.
Here is the exact architecture, the code, the trade-offs, and how you can run it yourself.
The AI Agent Trap in Web3
Every week on Twitter, someone shows off an "autonomous AI crypto agent."
The video is always the same: a developer writes a Python script, drops an OpenAI API key into a .env file, connects an Ethereum wallet with twenty dollars of testnet ETH, and asks the bot to swap tokens on Uniswap. Everyone claps.
I think giving an LLM an unrestricted private key is an accident waiting to happen.
Large language models are probabilistic text predictors. They are not deterministic state machines. They misinterpret ambiguous inputs. They hallucinate addresses. They are vulnerable to prompt injections hidden in on-chain transaction strings.
Blockchains are the exact opposite. Every transaction is binary, permanent, and mathematically final. Once your treasury tokens leave your Safe, no customer support team can reverse the transfer.
If you connect a probabilistic AI model directly to an irreversible execution wallet, you are asking to get wiped out.
The Correct Mental Model
You do not need an AI with signing authority.
You need an automated sentinel that handles the tedious operational grunt work:
- Ingesting event notifications 24/7 so humans do not have to refresh Safe all day.
- Checking deterministic rules (Did the threshold change? Is this a
DELEGATECALL? Is the recipient allowlisted?). - Using an AI model strictly as an explanation analyst to translate raw bytecode into human-readable briefs.
- Keeping all signing power in the hands of human multisig signers.
The AI proposes and explains. The blockchain and humans enforce.
Why n8n?
When I sat down to build this, I could have built a standalone microservice using Express, TypeScript, and a dedicated PostgreSQL database.
I deliberately chose n8n instead.
Why? Because operational tooling for crypto teams needs to be:
- Inspectable: Every node in the canvas can be visually audited by non-developers on the finance council.
- Self-Hostable: Teams can run it on their own private VPS or Docker container with zero third-party data leakage.
- Extensible: It ships with native HTTP request nodes, Cron schedulers, built-in Data Tables for persistence, and AI Agent nodes out of the box.
- Portable: The entire system lives in a single JSON file (
workflow/safe-treasury-sentinel.json). You import it into your n8n canvas, connect your credentials, and you are ready.
The System Architecture
The Sentinel operates across three distinct triggers:
flowchart TD A[Safe Event Webhook] --> B[Validate & Deduplicate] B --> C[Fetch Safe State & TX Details] C --> D[Deterministic Policy Engine] E[15-Minute Scheduled Cron] --> F[Fetch Current Safe State & Balances] F --> G[Diff Against Approved Baseline] G --> D H[Manual Demo Trigger] --> I[Synthetic Test Scenarios] I --> D D --> J[Evidence-Led Brief] J --> K[n8n AI Incident Analyst] K --> L[Record in n8n Data Table] L --> M[Optional Telegram Alert] Let's break down how the core pieces work under the hood.
1. Webhook Ingestion & Deduplication
Safe Infrastructure provides a webhook service that emits HTTP POST events whenever activity happens on your multisig.
The Sentinel exposes an authenticated webhook endpoint that listens for seven event categories:
-
PENDING_MULTISIG_TRANSACTION(a new proposal was submitted) -
NEW_CONFIRMATION(a signer approved a proposal) -
EXECUTED_MULTISIG_TRANSACTION(the transaction executed on-chain) -
NEW_DELEGATE/UPDATED_DELEGATE/DELETED_DELEGATE(access-control changes) -
MODULE_TRANSACTION(an automated smart account module moved funds) -
OUTGOING_ETHER/OUTGOING_TOKEN(funds left the treasury) -
REORG_DETECTED(a chain reorganization occurred)
Because distributed webhook deliverers can send duplicate messages during network retries, the workflow normalizes an event delivery identifier:
const deliveryId = String( event.id || event.safeTxHash || event.txHash || (type + ':' + safeAddress + ':' + (event.timestamp || Date.now())) ); It checks this identifier against an internal SafeSentinelDeliveries Data Table. If the delivery was already processed, it drops the duplicate immediately.
2. The 15-Minute Scheduled Baseline Reconciler
Webhooks are push notifications. What happens if Safe's webhook service experiences an outage?
That is why the Sentinel has a secondary, pull-based heartbeat. Every 15 minutes, a scheduled cron trigger fires. It queries the Safe Transaction Service API directly:
- Retrieves current owners and threshold.
- Pulls active modules and guard contracts.
- Retrieves the delegate registry.
- Checks pending multisig transactions.
- Ingests current ERC-20 token balances.
Catching Stealth Configuration Drifts
When you first deploy the Sentinel, you click a manual trigger called Capture Approved Treasury Baseline.
This snapshots your wallet's verified reference configuration into an n8n Data Table (SafeSentinelBaselines):
- Approved owners list
- Signing threshold (e.g., 3 of 5)
- Enabled modules
- Authorized delegates
- Guard contract address
- Fallback handler and master copy implementation
Every 15 minutes, the scheduled reconciler diffs the live Safe state against this approved baseline.
If an attacker compromises enough keys to submit a transaction that lowers your threshold from 3-of-5 to 1-of-5, or quietly enables a rogue Safe module, the reconciler catches the drift on the next cycle, flags it as CRITICAL, and raises an alarm.
3. The Deterministic Policy Engine (Before the AI Sees It)
Here is a foundational engineering rule: Never let an LLM decide whether an event is dangerous.
Large language models can be persuaded. Math and code cannot.
Before any data reaches the AI layer, our workflow routes all transactions through a JavaScript code node called the Deterministic Event Policy Engine.
This engine assigns an initial severity (INFO, MEDIUM, HIGH, CRITICAL) and a numerical risk score (0 to 100) based on strict, deterministic rules.
Here is a look at the policy logic:
// Excerpt from Deterministic Event Policy Engine let severity = 'INFO'; let score = 10; let reasons = []; let reviewRequired = false; // 1. Rogue Module Execution if (type === 'MODULE_TRANSACTION') { severity = 'CRITICAL'; score = 99; reasons.push('A Safe module executed an action. Modules bypass multisig thresholds completely.'); reviewRequired = true; } // 2. Dangerous DELEGATECALL Detection if (Number(tx.operation) === 1) { severity = 'CRITICAL'; score = 99; reasons.push('Transaction uses DELEGATECALL. This allows the target contract to rewrite Safe storage.'); reviewRequired = true; } // 3. Unapproved Recipient Check if (to && !approvedRecipients.includes(to.toLowerCase())) { severity = 'HIGH'; score = 90; reasons.push('Recipient address is not in the configured approved-destination list.'); reviewRequired = true; } // 4. Large Native Outflow if (type === 'OUTGOING_ETHER' && BigInt(valueWei) > BigInt(maxNativeTransferWei)) { severity = 'HIGH'; score = Math.max(score, 88); reasons.push('Native ETH transfer exceeds the configured single-transaction ceiling.'); reviewRequired = true; } Notice the check for tx.operation === 1. In Safe contracts, operation 0 is a standard CALL, while operation 1 is a DELEGATECALL.
If a pending transaction uses DELEGATECALL, the target contract executes in the context of your Safe's storage. It can overwrite the owner array or self-destruct the contract. The policy engine instantly flags this as a 99-score CRITICAL risk before any AI prompt is generated.
4. The AI Incident Analyst (The Plain-English Explainer)
Only after the deterministic facts, baseline diffs, and risk scores are assembled does the workflow pass the packet to the n8n AI Agent node.
The AI Agent connects to OpenAI (gpt-4.1-mini) with a strictly bounded system prompt:
- Explain the facts: Summarize what happened in clear, developer-friendly prose.
- Never downgrade: The AI is forbidden from lowering the severity assigned by the deterministic rules.
- Highlight missing data: If a webhook arrived without recipient details or calldata, explicitly say so.
- Action checklist: Provide a 3-point verification checklist for human signers.
Here is an example of what the AI output looks like when it flags an unapproved recipient proposal:
CRITICAL ALERT: Safe Proposal Requires Signer Review Safe: 0x12a4...b891 (Ethereum Mainnet) Severity: HIGH | Risk Score: 90/100 Summary: A new pending multisig transaction (nonce 42) was submitted by signer 0x89c...d41. The transaction proposes transferring 50,000 USDC to 0x742...12a. Findings: - Destination 0x742...12a is NOT in the approved treasury recipient list. - Value: 50,000.00 USDC. - Current signatures: 1 of 3 required. Signer Checklist Before Approving: 1. Contact proposer 0x89c...d41 on an out-of-band communication channel (Signal/phone). 2. Confirm whether destination 0x742...12a belongs to an approved vendor invoice. 3. Verify that the transaction calldata matches the expected ERC-20 transfer selector. 5. Persistence & Alerts
Every incident is persisted into an n8n Data Table called SafeSentinelIncidents.
This gives your operations team a queryable, permanent ledger of every alert, risk score, transaction hash, and AI explanation. If you configure a Telegram Bot token and chat ID in the settings, it formats the summary and pings your security channel instantly.
Honest Limitations: What This v1 Does NOT Do
I want to be completely transparent about what this repository is and what it is not.
It is a functional reference implementation and proof of capability. It is not an audited commercial product.
Here are the real limitations you should know before running it:
- Single-Chain Starter: The initial template is configured for one Safe on Ethereum Mainnet (
chainId: 1). If you run on Arbitrum, Base, or Optimism, you must update the service base URLs and chain IDs together. - Delivery Acknowledgment Timing: In the starter workflow, the webhook response is returned early to prevent Safe's webhook server from timing out. If downstream AI inference fails due to an OpenAI API error, the delivery was recorded, but the incident row might lack the full AI summary. A full production deployment requires a dead-letter replay queue.
- Baselines Need Honest Humans: If your Safe is already compromised when you click
Capture Approved Treasury Baseline, the Sentinel will snapshot the compromised state as the approved baseline. A human must independently verify the wallet on Etherscan before running baseline capture. - Read-Only by Design: The Sentinel cannot pause your Safe, cancel proposals, or move funds. It has zero keys. It is a watchdog, not an execution bot.
How to Try It Yourself
The entire project is open-source under the MIT license.
Step 1: Clone the Repo
git clone https://github.com/theweb3wizard/safe-treasury-sentinel.git Step 2: Import into n8n
- Open your n8n canvas.
- Click Workflow -> Import from File.
- Select
workflow/safe-treasury-sentinel.json.
Step 3: Configure Settings
Open the central configuration node labeled Configuration & Input Router - EDIT SAFE SETTINGS HERE:
- Set your
safeAddressandchainId. - Paste your verified
approvedRecipientsarray. - Connect your OpenAI credential to the AI node.
- Assign your Safe Transaction Service API headers.
Step 4: Run the Demo
Hit the Run Demo Scenarios... manual trigger. It feeds four synthetic scenarios (a rogue module execution, an unapproved recipient proposal, a native transfer spike, and a routine confirmation) through the engine so you can watch how the deterministic rules and AI analyst respond.
Final Thoughts
You do not need to build hundred-thousand-dollar custom microservices to maintain visibility over your treasury. And you certainly should not be giving private keys to language model loops.
By combining low-code workflow automation with deterministic policy checks and an isolated AI analyst, you get 24/7 surveillance while keeping your treasury's private keys safely locked inside your hardware wallets.
Check out the code on GitHub:
https://github.com/theweb3wizard/safe-treasury-sentinel
If you are running a protocol treasury or building Web3 automations, I would love to hear your feedback. What rules would you add to the policy engine?

