ByAUJay
“DAO Treasury Multisig” Forta Gnosis and “DAO Treasury Multisig” Forta: Monitoring Gnosis Safe Events
Quick summary: A concrete, end‑to‑end playbook for monitoring DAO treasury multisigs by wiring Forta alerts to Gnosis Safe (now Safe) events. We’ll show exactly which Safe events matter, how to subscribe or build a Forta bot, how to route alerts into Slack/Webhooks, and how to pair monitoring with Safe v1.5.0 Module Guards and Safe Shield to actually block malicious transactions. (github.com)
Why this matters now (January 2026)
- Safe v1.5.0 shipped material security features—including Module Guards, modernized EIP‑1271 validation, and an extensible fallback handler—making it easier to enforce global policies even on module‑initiated transactions. If your DAO upgraded from v1.3/1.4 or you’re deploying fresh Safes, your monitoring and prevention model should change accordingly. (github.com)
- Forta matured into a production detection layer with 1,000+ scan nodes across seven major EVM chains and 600+ active bots producing alerts that teams can subscribe to via email, Slack, Telegram, Discord, or custom webhooks. The General Plan grants API and notification access, and many “starter kit” bots cover Safe events out‑of‑the‑box. (forta.org)
- Safe Shield (enterprise protection powered by Hypernative plus transaction insights from providers like Blockaid/Tenderly) now surfaces risks before signers approve, complementing Forta’s post‑block alerting. DAOs should combine pre‑execution simulation and policy enforcement with post‑execution monitoring and forensics. (safe.global)
What exactly to monitor on a Safe multisig
Your treasury Safe emits canonical events whenever security‑relevant configuration or execution changes occur. Instrument these first:
- Owner and threshold changes
- AddedOwner, RemovedOwner, ChangedThreshold. Alert if quorum drops (e.g., 4‑of‑7 to 3‑of‑7), if any unrecognized owner is added, or if rapid owner churn occurs. (docs.safe.global)
- Execution outcomes
- ExecutionSuccess / ExecutionFailure indicate on‑chain execution status for multisig transactions; unexpected failures can hide reverts inside complex multisends or indicate blocked guards. (docs.safe.global)
- Module lifecycle and module executions
- EnabledModule / DisabledModule plus ExecutionFromModuleSuccess / ExecutionFromModuleFailure. Modules can bypass signer thresholds; in v1.5.0 you can add Module Guards to constrain them, but you should still alert on any module enable/disable and any module‑initiated execution. (docs.safe.global)
- Guard changes
- ChangedGuard when setGuard is called. Treat any guard removal or replacement as high severity. Broken or malicious guards can DoS or silently bypass policies. (docs.safe.global)
- Hash approvals
- ApproveHash events effectively whitelist a transaction hash forever (no revocation). Alert on any approval by non‑expected owners or outside normal maintenance windows. (docs.safe.global)
Tip: Safe v1.5.0 adds an extensible fallback handler and other internals; keep an eye on ChangedFallbackHandler as part of your baseline drift detection if you rely on handler‑based integrations. (github.com)
Two paths to Forta‑powered monitoring (pick one—or both)
Option A — No‑code: Subscribe to a Safe events bot in Forta
Forta’s “OpenZeppelin‑Gnosis Safe Contract Events” bot family emits alerts for security‑relevant Safe events across major EVM chains. Subscribe and route to Slack/Email/Webhook in minutes:
- In Forta App, find the OpenZeppelin‑Gnosis Safe Contract Events bot (oz‑gnosis‑events). Confirm supported networks (Ethereum, Polygon, Avalanche, Arbitrum, Optimism) and that your treasury chain is included. (docs.forta.network)
- Subscribe and filter by your Safe address(es). Choose notification channels. Forta supports Slack, Email, Telegram, Discord, and Webhook for paid plans; the General Plan covers API access and notifications. (docs.forta.network)
- Test by emitting a benign event (e.g., simulate a multisig tx on a staging Safe). Confirm alerts flow end‑to‑end.
- Optional: Chain extra starter‑kit bots, like “Monitor Function Calls” or “Time Series Analyzer,” to detect threshold decreases, bursts of owner changes, or unusual module activity. (docs.forta.network)
This gets you baseline coverage fast and federates nicely with other Forta feeds (stablecoins, bridges, timelocks) that might interact with your treasury. (docs.forta.network)
Option B — Low‑code: Build a tailored Forta bot focused on your policy
If you need custom severities, allowlists, and cross‑bot logic, write a small Forta Agent that listens to Safe events and enforces your DAO’s policy.
Minimal TypeScript example (filter a Safe for owner/threshold/module/guard changes and executions):
// forta-agent v0.x import { Finding, FindingSeverity, FindingType, HandleTransaction, getEthersProvider, ethers } from "forta-agent"; // Event signatures from Safe ABI const sigs = { AddedOwner: "event AddedOwner(address owner)", RemovedOwner: "event RemovedOwner(address owner)", ChangedThreshold: "event ChangedThreshold(uint256 threshold)", EnabledModule: "event EnabledModule(address module)", DisabledModule: "event DisabledModule(address module)", ChangedGuard: "event ChangedGuard(address guard)", ExecutionSuccess: "event ExecutionSuccess(bytes32 txHash, uint256 payment)", ExecutionFailure: "event ExecutionFailure(bytes32 txHash, uint256 payment)", ExecutionFromModuleSuccess: "event ExecutionFromModuleSuccess(address to,uint256 value,bytes data)", ExecutionFromModuleFailure: "event ExecutionFromModuleFailure(address to,uint256 value,bytes data)" }; const IFACE = new ethers.utils.Interface(Object.values(sigs)); const SAFE_ADDR = (process.env.SAFE_ADDR || "").toLowerCase(); const QUORUM_MIN = Number(process.env.QUORUM_MIN || 3); // policy floor export const handleTransaction: HandleTransaction = async (txEvent) => { const findings: Finding[] = []; for (const log of txEvent.logs) { if (log.address.toLowerCase() !== SAFE_ADDR) continue; let parsed; try { parsed = IFACE.parseLog(log); } catch { continue; } const { name, args } = parsed; if (name === "ChangedThreshold") { const t = Number(args.threshold); if (t < QUORUM_MIN) { findings.push(Finding.fromObject({ name: "Safe threshold decreased below policy", description: `Threshold set to ${t} (policy min: ${QUORUM_MIN})`, alertId: "SAFE-THRESHOLD-LOW", severity: FindingSeverity.High, type: FindingType.Suspicious, metadata: { threshold: String(t) } })); } } if (name === "AddedOwner" || name === "RemovedOwner") { findings.push(Finding.fromObject({ name: `Owner set changed: ${name}`, description: `${name} => ${args.owner}`, alertId: "SAFE-OWNER-CHANGE", severity: FindingSeverity.Medium, type: FindingType.Info, metadata: { owner: args.owner } })); } if (name === "EnabledModule" || name === "DisabledModule") { findings.push(Finding.fromObject({ name: `Module configuration: ${name}`, description: `${name} => ${args.module}`, alertId: "SAFE-MODULE-CHANGE", severity: FindingSeverity.High, type: FindingType.Suspicious, metadata: { module: args.module } })); } if (name === "ChangedGuard") { findings.push(Finding.fromObject({ name: "Guard changed", description: `New guard: ${args.guard}`, alertId: "SAFE-GUARD-CHANGE", severity: FindingSeverity.Critical, type: FindingType.Suspicious, metadata: { guard: args.guard } })); } if (name.startsWith("Execution")) { findings.push(Finding.fromObject({ name: `Safe execution: ${name}`, description: `Execution event ${name} on treasury Safe`, alertId: "SAFE-EXECUTION", severity: name.includes("Failure") ? FindingSeverity.Medium : FindingSeverity.Low, type: FindingType.Info })); } } return findings; };
Map event signatures to Safe docs for correctness and keep your policy thresholds configurable via env vars. This pattern works across Safe v1.4.1 and v1.5.0 and avoids ABI drift. (docs.safe.global)
How to route alerts and build dashboards your finance team will actually use
- Push notifications to Slack/Email/Webhooks from the Forta subscription UI; for deeper automation, pull alerts from the Forta GraphQL API and enrich with your internal signer roster and module allowlists. (docs.forta.network)
- Example: Forta GraphQL query to pull today’s alerts for your Safe address:
query todaysAlerts($input: AlertsInput) { alerts(input: $input) { alerts { alertId name protocol chainId source { bot { id name } } description metadata addresses projects severity createdAt } pageInfo { hasNextPage endCursor { blockNumber alertId } } } }
Variables:
{ "input": { "addresses": ["0xYourTreasurySafeAddress"], "severities": ["CRITICAL","HIGH","MEDIUM","LOW"], "createdSince": "startOfDay" } }
Use endCursor to paginate and build a simple Notion/Sheets export for weekly ops reviews. (forta-network.github.io)
- For “source of truth” on pending/executed transactions and signer confirmations, integrate the Safe Transaction Service or its Events Service webhooks. You’ll get structured events like NEW_CONFIRMATION and EXECUTED_MULTISIG_TRANSACTION that are perfect for reconciling against Forta alerts. (docs.safe.global)
Pre‑execution prevention belongs in your stack
Monitoring is necessary but insufficient. Add pre‑execution controls so that malicious or out‑of‑policy transactions never execute:
- Safe Shield
- Inline risk assessment and simulation in Safe UI; enterprise tier can automatically block policy‑violating transactions. Adopt it for signers who aren’t security engineers. (safe.global)
- Simulation providers
- Safe integrates Tenderly simulations at scale (~67k/month), giving signers and approvers clarity on state changes and expected gas before execution. Use simulation diffs as a required check in your runbook. (blog.tenderly.co)
- Guards and Module Guards (Safe v1.5.0)
- Pair a Transaction Guard with a Module Guard so both owner‑initiated and module‑initiated flows are enforced by the same policy. E.g., block “to” addresses not on an allowlist, cap stablecoin transfer sizes, or require a timelock for risky selectors. (safe.global)
Emerging best practices we’re implementing for DAOs in 2026
-
Monitor the seven “never ignore” Safe events
AddedOwner, RemovedOwner, ChangedThreshold, EnabledModule, DisabledModule, ChangedGuard, and all Execution* events. Set policy‑mapped severities: Critical for ChangedGuard and threshold below floor; High for module enables or owner churn; Info for benign ExecutionSuccess. (docs.safe.global) -
Alert enrichment before paging
Join alert payloads with:
- Current owners and threshold from Safe API.
- Known module allowlist.
- Recognized counterparties and token metadata.
This reduces noise and shortens triage time. Use Safe Transaction Service APIs for authoritative transaction/confirmation data. (docs.safe.global)
-
Safe v1.5.0 by default for new deployments
v1.5.0 introduces Module Guards, improved signature validation, and extensible fallback handler support—less footguns, better composability. Existing DAOs should plan an upgrade path and adjust guards/modules accordingly. (github.com) -
Pair Forta alerts with blocking policies
Backstop Forta post‑block alerts with Safe Shield and on‑chain Guards that can auto‑block or require escalation for out‑of‑policy txs. Forta alerts become your audit trail and early warning for config drift. (safe.global) -
Watch ApproveHash and snapshot‑to‑execution bridges
ApproveHash is irrevocable; alert whenever used. If you use Snapshot + SafeSnap/Reality, monitor module executions to ensure only proposals with valid oracles execute after cooldowns. (docs.safe.global) -
Roles and modules: least privilege
If you adopt Zodiac Roles or other modules for operational speed, scope permissions down to contract, selector, and parameter ranges; rate‑limit where feasible; instrument ExecutionFromModule* to catch abuse. (docs.roles.gnosisguild.org) -
Multi‑chain parity
Most treasuries span Ethereum plus L2s (Arbitrum/Optimism/Polygon). The oz‑gnosis‑events bot covers these; verify coverage and subscribe per address per chain. Build dashboards keyed by chainId to avoid blind spots. (docs.forta.network)
Practical, policy‑driven alert rules you can copy
- Threshold policy
If ChangedThreshold.threshold < policy_min OR (owners_count − threshold) < margin_of_safety → Critical, page Security On‑Call. (docs.safe.global) - Owner changes
If {AddedOwner or RemovedOwner} outside maintenance window → High; if within window but >1 change per 24h → Medium with “anomaly” label (Time Series Analyzer). (docs.forta.network) - Modules
If EnabledModule NOT IN allowlist → High; if DisabledModule of a Guard/Module Guard → Critical. (docs.safe.global) - Guards
Any ChangedGuard → Critical with auto‑escalation and immediate Safe Shield policy review. (docs.safe.global) - Executions
ExecutionFailure bursts (>N failures in 10 min) → suspect guard misconfig or griefing; raise Medium to investigate. ExecutionFromModule* always tagged with module address and decoded selector for review. (docs.safe.global) - ApproveHash
Any ApproveHash by an unknown owner or from a fresh EOA (<7 days old) → High. (docs.safe.global)
Example: 48‑hour rollout for a $100M DAO treasury
Day 1 (3–4 hours)
- Identify all treasury Safes (mainnet + L2s) and enumerate current owners, threshold, guards, modules.
- Subscribe to oz‑gnosis‑events in Forta for each address; route to #treasury‑alerts Slack and a Webhook. (docs.forta.network)
- Stand up a simple Forta Agent (like the snippet above) with your policy thresholds and module allowlist. Deploy and stake minimal FORT to activate.
- Connect Safe Events Service webhook to your internal incident system for confirmations/executions feed. (github.com)
Day 2 (3–4 hours)
- Enable Safe Shield on all production signer UIs; configure automatic block for known bad destinations and policy‑violating transfers. (safe.global)
- Add a Module Guard in v1.5.0 to mirror your Transaction Guard policy for module‑initiated flows. (safe.global)
- Build a Notion/Sheets dashboard fed by Forta GraphQL with weekly owner/threshold/module drift reports. (docs.forta.network)
Don’t forget simulation and human factors
- Require a successful simulation (Tenderly or equivalent) as a checklist item before approval, especially for high‑value multisends or module transactions. Push the simulation diff into the Slack thread with the Forta alert for context. (blog.tenderly.co)
- Educate signers that Safe Shield’s “High risk” is a stop sign, not a suggestion. Enforce this norm with guard logic where feasible. (safe.global)
Chains, scale, and reliability notes
- Supported networks: Forta scan nodes cover Ethereum, Polygon, Avalanche, BNB, Arbitrum, Optimism, and Fantom, with thousands of alerts flowing hourly. Ensure your Forta plan and RPC throughput can handle your alert volume. (forta.org)
- Node and plan hygiene: If you run your own Forta scan node (for dedicated latency), configure JSON‑RPC endpoints per chain (Blast/Bware) and maintain the 2,500 FORT minimum stake for scan nodes. Subscriptions via the General Plan (~250 FORT) cover API and notifications. (docs.forta.network)
Extra: pulling Safe events directly when you need them
Even with Forta in place, sometimes you need raw event logs or indexed data:
- Safe Transaction Service “List Transactions” and “Module Transactions” endpoints provide canonical history (pending/executed/failed) per Safe with pagination and failure flags—great for reconciling after incidents. (docs.safe.global)
- Safe Events Service webhooks give real‑time JSON for NEW_CONFIRMATION, PENDING_MULTISIG_TRANSACTION, and EXECUTED_MULTISIG_TRANSACTION—you can mirror these to Forta alerts for a unified incident channel. (github.com)
Security hardening checklist (copy/paste)
- Safe contracts on v1.5.0 where feasible; confirm Guards + Module Guard are active and tested. (github.com)
- Subscribe oz‑gnosis‑events for all treasury Safes; route to Slack/Webhook. (docs.forta.network)
- Custom Forta bot enforcing your policy (threshold floors, module allowlist, guard changes).
- Safe Shield enabled for all signer UIs with automatic block on policy violations. (safe.global)
- Simulation required for high‑risk transactions; evidence attached to approval thread. (blog.tenderly.co)
- Webhooks from Safe Events Service to your incident system; weekly drift report from Forta GraphQL. (github.com)
- Incident playbook: what to do on ChangedGuard/EnabledModule/Threshold drop (freeze flows, raise threshold, rotate owners).
- Regular table‑top exercises on signer compromise and module abuse.
Closing
A DAO’s treasury is only as safe as its change control. By aligning Forta’s real‑time detection with Safe’s v1.5.0 prevention primitives (Module Guards, Guards, Safe Shield), you can move risk left—blocking malicious activity before it executes—and still keep a durable audit trail and analytics pipeline for operations. Start with the starter bot subscription, add a thin custom policy bot, and enforce with guards: that’s a deployable 48‑hour roadmap for most teams. (docs.forta.network)
References and further reading
- Safe v1.5.0 release notes and docs on events and guards. (github.com)
- Forta: network overview, subscriptions, API GraphQL, and “oz‑gnosis‑events” starter. (docs.forta.network)
- Safe Shield and simulation integrations (Hypernative, Blockaid, Tenderly). (safe.global)
- Safe Transaction Service and Events Service (webhooks). (docs.safe.global)
- Forta network growth and supported chains. (forta.org)
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

