Inspiration Every SOC team faces the same impossible dilemma: AI agents need access to Splunk to investigate security incidents, but giving an autonomous system unrestricted access to every log index, SPL query, and alert feed is a privilege escalation risk waiting to happen. Lock down the agent and it can't investigate. Open the floodgates and the blast radius is unbounded. We realized that the missing piece isn't better AI — it's better authorization. Specifically, the kind of fine-grained, relationship-based authorization that powers Google's internal access control system. That's Zanzibar. AuthZed's SpiceDB is the open-source Zanzibar implementation, and when the Splunk Agentic Ops Hackathon was announced, the answer was obvious: put a Zanzibar-style permission engine between every AI agent and every Splunk tool call. No more all-or-nothing access. No more praying that prompt instructions keep the agent in bounds. Every splunk_run_query, every splunk_get_alerts, every splunk_get_indexes — checked, allowed, or denied — before a single log line ever reaches the agent.
What it does ShieldGate is a least-privilege authorization gateway that sits between AI agents (and human analysts) and Splunk, enforcing per-tool, per-index, per-query access control using AuthZed SpiceDB's Zanzibar-style ReBAC (Relationship-Based Access Control). The system supports five distinct roles — SOC Tier 1, SOC Tier 2, SRE, Contractor, and AI Agent — each with a unique permission profile that governs which of Splunk's 11 MCP tools they can invoke, which indexes they can read or query, and what data transformations (like redaction) are applied.
Key capabilities include:
Pre-execution authorization — denied queries never hit Splunk. Every tool call passes through a permission check that evaluates tool access, index membership, and conditional constraints in a single decision. Per-index isolation — SRE engineers can query observability but are blocked from security. Contractors can read (redacted) security incidents but cannot run ad-hoc SPL queries. SOC Tier 1 gets limited SPL (no subsearches, no eval expressions). Contractor data redaction — sensitive fields (source IPs, usernames, geolocation, hashes) are automatically stripped from results at the authorization layer. No application code changes needed. AI incident investigator — a chat interface powered by LLM suggests SPL queries, correlates events across indexes, and recommends containment steps — all constrained by the same permission engine. Real-time AuthZ audit trail — every ALLOW/DENY decision is logged with timestamp, role, action, target resource, and policy reason, giving compliance teams a complete timeline of who accessed what and why. How we built it ShieldGate is a Next.js 16 application with React 19, TypeScript, and Tailwind CSS 4, using shadcn/ui components for a professional SOC-dark UI. The architecture has three layers:
Authorization engine (src/lib/authz.ts) — implements the full Zanzibar-style permission model with a SpiceDB schema defining user, team, splunk_index, splunk_tool, and incident definitions with computed permissions via relation traversal (e.g., permission execute = allowed_user + allowed_role->member_access - restricted). The permission check function evaluates tool access, then index membership, then returns an AuthZDecision with allow/deny, reason, policy type, and timestamp. API gateway — seven Next.js API routes that enforce AuthZed checks before proxying to Splunk: POST /api/authz/check — generic permission check endpoint POST /api/splunk/query — SPL query with pre-execution AuthZ gate + contractor redaction GET /api/splunk/indexes — index listing filtered by role POST /api/splunk/alerts — alerts filtered by role and index access GET /api/incidents — incident listing with role-based visibility GET /api/audit — authorization audit trail POST /api/chat — AI investigator with incident context, powered by z-ai-web-dev-sdk Splunk simulation layer (src/lib/splunk-sim.ts) — since a live Splunk instance isn't available for the demo, we built a realistic simulation engine with 25+ synthetic security events across three indexes (security, observability, compliance), an SPL parser that handles stats count by, sourcetype filtering, severity filtering, and field extraction, plus a redactEvents() function that strips IPs, usernames, hashes, and geolocation data for contractor views. The frontend features a three-panel layout: incident list (left), AI chat + evidence/SPL/AuthZ tabs (center-right), and a live SpiceDB schema viewer (bottom). Role switching instantly re-evaluates all permissions — incidents get locked, queries get denied, results get redacted — all in real-time. State management uses Zustand, and the database layer uses Prisma with SQLite for the audit trail.
The complete demo seeds 12 realistic security incidents (data exfiltration, brute force, impossible travel, privilege escalation, OOM kills, SQL injection, pass-the-hash, HIPAA violations, SOC2 failures) with raw event data and assigned teams.
Challenges we ran into The biggest challenge was modeling Zanzibar-style relationship inheritance correctly. In SpiceDB, permissions are computed by traversing relations — for example, incident.view = viewer + assigned_team->member_access + index->read means an incident is viewable not just by its direct viewers, but by any member of its assigned team AND by anyone who has read access to its source index. Getting these computed permissions right without a live SpiceDB instance meant implementing our own relation traversal engine that mimics SpiceDB's behavior, including the subtraction operator (- restricted) for exclusionary policies.
A second challenge was the Splunk MCP Server integration. The Splunk MCP Server exposes 11 tools (splunk_run_query, splunk_get_indexes, splunk_get_alerts, splunk_ai_assistant, etc.), and each one needs independent permission rules that vary by role. Building the permission matrix for 5 roles × 11 tools × 5 indexes with conditional constraints (limited SPL, observability-only alerts, redacted results) required careful mapping to avoid either over-permissive or overly restrictive configurations.
The contractor redaction layer was also tricky — we needed to intercept results after the Splunk query returns but before they reach the client, and apply field-level redaction without modifying the underlying data model. This required a dedicated redactEvents() function that sanitizes IPs via regex, replaces sensitive field values with [REDACTED], and strips raw log lines — all transparent to the rest of the application.
Accomplishments that we're proud of We're most proud of the end-to-end authorization flow — from the moment a user (or AI agent) clicks "Run Query" to the AuthZed decision appearing in the audit trail, the entire pipeline is clean and real: permission check → allow/deny → audit log → conditional data transformation → UI update. There's no fake middleware or "simulated authorization" — the decision logic is the same pattern that production Zanzibar systems use.
The role-switching experience is particularly satisfying. Switching from SOC Tier 2 to Contractor in the dropdown instantly locks incidents, denies queries, redacts results, and updates the permission timeline — making the authorization model tangible and visible rather than abstract.
We also built a realistic Splunk simulation that parses actual SPL syntax (filtering, stats, aggregations) and returns plausible security events — making the demo feel like a real SOC tool rather than a UI mockup.
What we learned We deepened our understanding of Zanzibar's relationship-based access control model, specifically how computed permissions like permission view = viewer + assigned_team->member_access + index->read create powerful authorization patterns that are impossible to express in traditional RBAC systems. The realization that index->read in the incident definition means "anyone who can read the index can view incidents within it" was a breakthrough moment — it shows how Zanzibar turns data relationships into access decisions.
On the Splunk side, we learned the full scope of the Splunk MCP Server's 11 tools and how they map to real SOC workflows. Understanding that splunk_get_kv_store and splunk_get_lookup are more sensitive than splunk_get_indexes (which should be readable by all roles) informed our permission matrix design significantly.
We also learned that building effective AI agent guardrails requires a fundamentally different approach from human access control. Agents don't respect UI boundaries or "soft" instructions — they need structural constraints at the API level. ShieldGate demonstrates that Zanzibar-style ReBAC is the right primitive for this problem.
What's next for ShieldGate Live AuthZed SpiceDB integration — replace the simulation layer with actual gRPC calls to AuthZed Cloud (or self-hosted SpiceDB) using the @authzed/authzed-node SDK, enabling real relationship writes, schema management, and consistency checks Splunk MCP Server live connection — swap the simulation layer for a real Splunk MCP Server connection, so queries execute against actual security data Just-in-time permission elevation — allow AI agents to request temporary elevated access (e.g., "I need to query the compliance index for this investigation") with human approval workflow and automatic expiration Anomaly detection on AuthZ decisions — flag unusual permission patterns (e.g., an AI agent suddenly requesting access to an index it's never queried before) as potential compromise indicators Multi-tenancy — extend the schema with organization definitions so ShieldGate can serve multiple SOC teams with isolated permission namespaces Policy editor UI — a visual schema editor where security architects can modify the SpiceDB Zed schema, adjust role permissions, and preview the effect on incident access without writing code
Built With
- authzed
- motion
- next.js-16
- orm
- prisma
- query
- react-19
- spicedb
- splunk
- sqlite
- tanstack
- typescript
- zustand

Log in or sign up for Devpost to join the conversation.