Skip to content

Security

A security tool that overstates its boundary is worse than none, because people rely on the part that was never true.

Trust boundary

What Zence is, stated precisely

Zence reduces accidental and agent-mediated mistakes inside the supported Claude Code workflow. It is not a kernel sandbox, not an endpoint security product, and not a substitute for warehouse permissions.

Not intercepted

The same query run in a shell, a notebook, or a BI tool. Zence sits in Claude Code’s hook path and nowhere else.

Not tamper-proof

Policy files live in the workspace. Zence refuses edits from inside a governed session and audits the attempt, but it does not defend against someone editing them out of band.

Not your first line

Correct grants in Snowflake or BigQuery remain the primary control. Zence catches what those cannot: a mistake made by someone who does have access.

When it cannot see

Ignorance never becomes permission

If a lookup fails, if a reference will not resolve, if an asset sits outside the boundary and no rule happened to cover it — the answer is ask, not allow.

Fail-safe behaviour by situation
SituationResult
Explicit high-risk violationdeny
DataHub unreachable during a data operationask, and it says the catalog was unreachable
DataHub unreachable, no assets referencedallow, flagged as degraded
Asset named but unresolvable, during a writeask
Resolved, outside the boundary, no rule matchedask
The hook itself crashes or times outask on data-touching tools; quiet on a local read
Cross-client reference with a failed lookupask, never allow

A crash is answered with ask only for tools that can touch data. Failing closed on everything would make a Zence bug indistinguishable from a policy violation, and train people to click through prompts — which is how a guardrail stops working.

Threat model

Specific threats

Prompt injection via catalog metadata
A dataset description is data, not instructions. Metadata is rendered as quoted, length-bounded text with newlines collapsed, and policy decisions read typed fields only — never free text.
Untrusted MCP output
Responses are schema-validated. An unexpected shape routes to ask rather than being parsed optimistically.
Token theft
The DataHub token lives in the system keychain via the plugin's userConfig, is never written to a workspace file, never logged, and never printed by the CLI. A test asserts it.
Path traversal and symlinks
Containment is checked after full resolution, so ../../etc/passwd and a file symlinked to .zence/policy.yaml are both caught. A path Zence cannot locate is treated as tampering.
Shell injection
Commands are parsed with shlex and never executed. Zence reads them the way a linter does.
Disabling Zence from inside a session
Edits to .zence/** and to Claude Code's hook configuration are denied, and that rule is triggered by a hardcoded flag rather than a policy condition — so it survives audit mode and cannot be waived by an exception.
Duplicate or replayed write-back
The DataHub document id is derived deterministically, so finalizing twice updates one record rather than creating two.
Failing open on an outage
The failure this project exists to prevent. A transport error is never reported as 'not in the catalog', and a rule that reads asset properties will not fire against evidence that failed to resolve.

Report a vulnerability through a private GitHub advisory, not a public issue.