Votal Shield — Sales Battle-Card
A one-page reference for live customer calls. Each entry: the objection, the mechanism-first answer, the follow-up jab they’ll throw, and a ⚠️ verify note where you must confirm shipped-vs-roadmap before promising.
Two rules that win every call:
- Lead with the mechanism, not the conclusion. Say “No/Yes” then immediately “…because here’s how it works.”
- Calibrated honesty beats overclaiming. “That’s roadmap” / “that’s policy-driven” / “no one’s 100% on injection” builds more trust with security and compliance buyers than a confident claim that gets caught.
The one-sentence frame: Your IdP authenticates your humans; Shield sits downstream and governs what your agents are allowed to actually do — per action, short-lived, scoped, revocable, and audited.
Personas & what they probe
| Persona | Cares about | Favorite trap |
|---|---|---|
| 🛡️ Security Architect | Trust model, key handling, blast radius | “What happens when X is stolen?” |
| ⚙️ Platform Engineer | Latency, throughput, failure modes | “What breaks at scale / when you’re down?” |
| 📋 Compliance / GRC | Audit, residency, standards | “Prove it for my auditor.” |
| 💰 Skeptical CTO / Buyer | Differentiation, lock-in | “Why not just use Okta / my gateway?” |
| 👩💻 Integrating Developer | How to wire it up | “Show me the 3 calls my code makes.” |
ROUND 1 — Foundations
Q1 · Developer — “What do I give you, what changes in my code?”
Three things, only the first is one-time:
- One-time: register your Keycloak with us — issuer URL + client ID. We auto-discover the rest.
- Per process: take the user’s existing IdP login, call us once to mint a short-lived agent token (proves who, ~15 min, cached & reused).
- Per action: right before a real action (send email, move money), mint a capability; the tool verifies it. SDK wraps all three.
Jab — “Days or weeks?” → “Hours. Pip-installable SDK, three methods; Keycloak registration is one API call or a portal form.”
Q2 · Security Architect — “Do you ever see passwords or our private keys?”
No — and structurally impossible, not just policy:
- Your LDAP/AD never touches us — it stays behind Keycloak, in your network. We don’t speak LDAP.
- We only hold your IdP’s public keys, pulled from your standard JWKS endpoint. Public keys verify signatures, can never forge or decrypt.
- We see a signed badge your Keycloak already issued, and we check the signature. That’s the whole trust relationship.
Jab — “If YOU get breached?” → “Attacker gets our public keys (already public) and tokens that expire in minutes. They can’t impersonate your users — that needs your IdP’s private key, which we never have.”
Q3 · Platform Eng — “A round-trip on every LLM call? That’s latency + a SPOF.”
Premise is wrong — we do NOT touch your LLM calls:
- Agent token minted once per process, cached ~15 min, reused across thousands of calls — effectively free.
- We’re only in the path on an action (send_email, transfer_funds). Even there, crypto is ~50µs vs an LLM call of ~1s+ — ~30,000× faster than what it protects.
- Tool servers can verify capabilities locally with our public key — no call to us. You decide which tools even need a cap; trivial reads skip it.
Jab — “And if you’re down during a dangerous action?” → bridges to Q4.
ROUND 2 — The hard round
Q4 · Platform Eng — “If Shield is down, does the payment go through or block?”
You choose, per tool — fail-closed vs fail-open:
- Fail-closed = can’t authorize → action blocked (safe).
- Fail-open = unreachable → action allowed (available).
- Set fail-closed for payments/deletes, fail-open for low-risk reads. Dangerous actions stay protected even during an outage. Local cap verification means a dead control plane doesn’t stop already-issued caps.
Jab — “Default if I configure nothing?” → “Fail-closed on anything that mutates state. Secure by default; opt into fail-open.” ⚠️ Verify your deployment actually defaults fail-closed for state-changing tools before promising it.
❌ Never say “your apps can run unauthorized calls.” Say “fail-closed by default, configurable per tool.”
Q5 · CTO — “Why not just use my Okta OAuth scopes?”
Agents break three OAuth assumptions:
- One token = one principal. An agent action has a human + an agent + often a delegating parent. OAuth carries one subject; we carry the whole chain.
- Permission = identity only. OAuth can’t say “send_email but only internal, only once, only if no PII leaks.” Safety depends on what’s in the action, not just who calls. We decide per-action with context.
- Static & long-lived. OAuth access token = broad, ~1hr. Our cap = one tool, one resource, one use, 60s. If injection hijacks the agent, OAuth is a skeleton key; our cap opens one door once.
“Keep Okta — it authenticates your humans. We sit downstream and govern what the agent does. We federate with your IAM, we don’t replace it.”
Jab — “Isn’t a layer on top just more complexity?” → “The alternative is hard-coding tool perms into every agent and hoping nobody injects them. We make it policy — auditable and revocable in one place.”
Q6 · Compliance — “Show every action by this user Tuesday, and prove no tampering.”
Two parts — answer both:
- Produce it: one signed audit row per action (not per session), tagged
trace.id,agent.key,tenant_id,user_sub. Filter by user + date is a query. Flows to your SIEM (Splunk / Elastic / OTLP) — lives in your system of record. - Integrity: each decision row is signed so you can verify/replay the original. For hard immutability, stream to write-once storage (object-lock / append-only).
⚠️ Verify: signed per-action rows + SIEM export ship today; immutable write-once storage is roadmap in the docs. Say “signed rows + SIEM today; immutable storage on roadmap / available with X.” Never demo an overclaim to an auditor.
ROUND 3 — Closing-stage
Q7 · Security Architect — “Prompt injection emails customer data to an attacker. Where does it die?”
Defense-in-depth — attacker must beat all of these:
- Exact-scope cap — bound to specific tool + resource + recipient scope.
attacker@evil.comis outside scope → mint denied / verify rejects. Can’t widen an issued cap. - RBAC + clearance ceiling — exfiltrating
confidentialdata above the role’s ceiling is denied before any cap mints. - Output guardrails — PII detection/redaction catches customer records on the way out, regardless of caller.
- Taint tracking — data tagged by origin; sensitive (“tainted”) data is blocked from flowing to an external sink.
- Per-action audit — every denial (even the attempt) is logged and alertable.
Honest close: “No one’s 100% on prompt injection — it’s open research. We make a single injection insufficient: the attacker must break multiple independent controls, and every attempt is logged.”
Jab — “Which are on by default?” → ⚠️ Verify per tenant. Scope + RBAC are intrinsic to the cap system. Output redaction & taint tracking exist (taint_tracking.py, data_access_guard.py, role_redaction.py) but are toggleable per-tenant policy — say “we enable them during onboarding for an exfiltration threat model.” Don’t claim all five are on out-of-the-box unless confirmed.
Q8 · CTO — “How hard to rip you out? Are my agents permanently dependent?”
Low lock-in by design:
- Standards, not proprietary — tokens are plain JWT (RFC 7519) with a published JWKS; integration is standard OAuth 2.1 / RFC 8693. Any JWT library reads them.
- Your identity stays yours — root of identity is your Keycloak/LDAP, untouched if you remove us. We’re downstream.
- Tiny surface — three SDK calls. Removing us = deleting an integration, not unwinding a dependency. No state stored inside your agents.
- On-prem — you run it; no SaaS we can pull.
Jab — “What do I lose if I remove you?” → “Per-action authorization, guardrails, and the audit trail — agents go back to trusted-by-default. You don’t lose access, identity, or data. We’re additive.”
Q9 · Platform Eng — “Agent swarms: who did what, and can a sub-agent exceed the orchestrator?”
Two mechanisms — visibility + containment:
- Delegation chain (visibility): every agent has its own
agent_id+ uniqueagent_instance_id; sub-agents carryparent_agent_idback to the orchestrator, and caps carryparent_cap_id. Reconstruct the whole tree — every action, who delegated it, up to which human. - Scope intersection (containment): a delegated cap is always a subset of the parent’s authority — never a superset. Downstream can narrow, never widen. A confused/compromised sub-agent is capped at-or-below its parent.
- Plus delegation-depth and budget controls so one orchestrator can’t fan out into runaway tool calls.
Jab — “Kill just sub-agent #7 without taking down the swarm?” → “Yes — revoke that agent_instance_id, dead within ~1s on its next action; others keep running. Three kill switches: one instance, one user (user_sub), or one token (jti).”
⚠️ Verify: primitives exist (scope/delegation_control.py, scope/scope_boundaries.py, scope/budget_controls.py, parent_agent_id/parent_cap_id claims). Confirm scope-intersection is enforced at mint time in your build before saying “mathematically capped” — else say “enforced by policy.”
Reflexes to drill
- Kill-chains beat walls — for “can attacker do X,” list independent layers that must all fail.
- Turn exit/SPOF questions into value — “how do I leave” → “here’s what you’d give up”; “single point of failure” → “here’s where we’re not in the path.”
- Calibrated honesty — every ⚠️ is a spot where the honest answer wins the security/compliance buyer.
Glossary (fast)
AuthN = who you are · AuthZ = what you may do · LDAP/AD = your internal user directory · IdP (Keycloak/Okta) = login system in front of LDAP · OIDC = standard for issuing/checking login badges · JWT = the signed badge · JWKS = public page of the IdP’s public keys (what we “sync”) · Agent token = Shield badge proving who (~15 min, per process) · Capability/cap = one-action permit (≤60s, single-use) · Nonce = one-time value that blocks replay · RBAC = permissions by role (from LDAP group) · Clearance = data sensitivity ceiling · Revocation = instant kill switch (instance / user / token).