Skip to main content
Back to Blog
Open Source

Introducing Zift: Open-Source Authorization Code Scanner

Introducing Zift, an open-source authorization code scanner. It finds every access decision in your codebase and calculates your externalization percentage.

Mark Rogge, CEO8 min read
EnforceAuth Zift open-source announcement showing the scan-to-enforce pipeline: codebase scan, surface 7 authorization patterns, emit OPA-ready Rego stubs, enforce with runtime policy-as-code. Apache 2.0 licensed.

We ran our new scanner against a small, well-maintained financial application last month. Good engineering team. Policy engine in place. Clean abstractions. Exactly the kind of codebase you'd hold up as an example of how to do things right.

Twenty percent.

That was the share of authorization decisions actually routed through a policy engine. One in five. Everything else lived scattered across the source: role checks in decorators, attribute predicates buried in middleware, ORM ownership filters, business-rule guards, feature flags doubling as access controls, and bespoke per-application policy languages nobody documented.

We picked that codebase because we expected the number to be high. It wasn't.

What Is Zift?

Zift is a code scanner for authorization. It is open source under Apache 2.0, and it ships today.

Point it at your codebase. Zift parses across the languages and frameworks your application actually uses, identifies every authorization decision point it can find, and produces two things. First, an externalization percentage that tells you how much of your authorization surface is already centralized in a policy engine. Second, a Rego scaffold for everything that isn't centralized yet.

Parsers ship in the repository, the rule corpus is forkable, and the Rego emission engine is included. No telemetry, no phone-home, no signup, and in default mode, zero network calls whatsoever. Audit the binary. Run it air-gapped. Verify the number before any conversation with us ever happens.

Why Does Externalization Percentage Matter?

Authorization, in most enterprises, lives inside application code. A careful human reader can sometimes trace the logic. Centralized governance cannot. Auditors cannot. Runtime enforcement certainly cannot.

Ask a security team how much of their authorization is centralized and you'll get one of two answers. A shrug, or a number somebody made up in a meeting. Honest answers require a multi-week code archaeology project nobody has time for, and results go stale before the spreadsheet gets shared.

Externalization percentage changes that. One measurable number: authorization decisions routed through a policy engine versus decisions embedded directly in application code. Not a pass/fail audit, but a vital sign you can track over time as you migrate logic into centralized policy.

Nobody puts this metric on a board slide right now. By 2028, we think it will sit alongside MTTD and MTTR on every CISO's quarterly report. Companies that started measuring in 2026 will own that conversation. And those that didn't will be explaining why they can't produce the number.

How Does Zift's Two-Pass Architecture Work?

Zift scans in two passes. The distinction matters because authorization logic ranges from trivially obvious to deeply buried, and a single approach cannot catch both ends of that spectrum.

Pass 1: Structural Scanning

Pass one uses tree-sitter for fast, deterministic pattern detection. It catches authorization patterns that follow recognizable code structures: @RequiresRole annotations in Java, authorize() middleware calls in Express, [Authorize] attributes in C#, permission guard decorators in Python, and similar patterns across Go and TypeScript.

Fast, fully local, deterministic. No network access, no external service calls, and results you can reproduce on every run.

For many codebases, this first pass alone surfaces the vast majority of authorization decision points. Supported languages: TypeScript/JavaScript, Java, Python, Go, and C#.

Pass 2: Deep Semantic Scanning

Some authorization logic does not follow clean patterns. An ORM query that filters rows by owner_id is an authorization decision, but it looks like a database query. Same for a conditional checking user.tier === 'enterprise' before revealing pricing data. And feature flags that gate functionality by tenant? Access controls wearing a different hat.

Pass two, triggered with --deep, uses LLM-assisted analysis to catch these subtler patterns and extends language coverage to Kotlin, Ruby, and PHP. You can connect it to an LLM through MCP servers (Claude Code, Cursor, Continue, Cline, Zed), OpenAI-compatible HTTP endpoints, or custom subprocess agents.

Deep mode is optional. Some teams will never need it. But if your externalization percentage from the structural pass looks suspiciously high, deep mode often reveals the authorization decisions hiding in plain sight.

What Does Zift Find in a Typical Scan?

Zift identifies seven categories of authorization decision points across a codebase:

  • Role checks (annotations, decorators, explicit conditionals)
  • Permission guards and middleware
  • Attribute-based predicates (ABAC patterns in business logic)
  • ORM ownership and tenant filters
  • Business-rule guards (pricing tiers, feature entitlements, workflow state checks)
  • Feature flags functioning as access controls
  • Custom per-application policy languages and DSLs

For each decision point, Zift classifies whether it is already externalized to a policy engine or embedded in application code. Embedded ones get a corresponding Rego stub in the output scaffold, giving you a head start on migrating them to OPA. Cedar support is planned.

How to Get Started with Zift

Installation takes about thirty seconds. Pick your package manager:

brew install enforceauth/tap/zift # or cargo binstall zift

Prebuilt binaries are also available for Linux, macOS, and Windows from the GitHub releases page.

Run your first scan:

zift scan ./your-codebase

That gives you a structural scan with your externalization percentage and a breakdown by authorization pattern type. For deeper analysis:

zift scan ./your-codebase --deep

Start small. Pick one bounded context: a single application, one microservice, one regulated data domain. Get a baseline number and then decide what to do with it.

Why Apache 2.0?

We could have made Zift source-available, and plenty of companies in this space would have. Could have gone BSL, or the "open core with a sharp pricing edge" model that has become fashionable. We chose Apache 2.0 deliberately.

Here's why. Discovery in authorization governance is too important to gate behind a procurement cycle. If a security team needs to file a purchase order and schedule a vendor call before they can find out how much of their authorization is actually centralized, most of them will never find out. So the question stays unanswered, and the risk stays unmeasured.

Fork the rule directory, modify the parsers, integrate it into your CI pipeline, ship it to your compliance team. We want this number to exist in every organization regardless of whether they ever talk to us.

And we drew a clear line between Zift and the EnforceAuth runtime. Zift is the on-ramp. It tells you where you stand. And the runtime is the highway, enforcing fine-grained policy across applications, infrastructure, data, and AI workloads at sub-50ms latency in production. Genuinely useful on its own. That was the bar.

The Authorization Problem Zift Exposes

Every AI strategy currently under construction quietly assumes that authorization works. It does not.

At an 82:1 non-human-to-human identity ratio in the average enterprise, static role checks cannot hold. Policy change cycles run at release cadence, not at policy cadence. And the audit question, "how much of our authorization is actually governed?", takes weeks of manual code review to answer. Zift answers it in minutes.

We built EnforceAuth because authentication is solved and authorization is not. Okta, Entra ID, Auth0, and dozens of others handle the first question well: who are you? But the second question, what are you allowed to do right now, for this action, against this resource, is where most enterprises have no enforcement at all. Especially for non-human identities.

Zift makes that gap measurable for the first time. A concrete number, not a gut feeling. And once you have a number, you can start having an honest conversation about what to do about it, whether that means migrating policy into OPA on your own, evaluating commercial solutions, or just putting the baseline on a slide so your board knows where you stand.

Common Questions About Zift

What is externalization percentage?

Externalization percentage is the ratio of authorization decisions in your codebase that are routed through a centralized policy engine (like OPA or Cedar) versus those embedded directly in application code as role checks, middleware guards, ORM filters, or business-rule conditionals. A codebase with 20% externalization has one-fifth of its authorization decisions centralized and four-fifths scattered across source code.

Does Zift send any data externally?

No. In default mode, Zift makes zero network calls. It runs entirely locally against your source code. If you enable --deep mode, it connects to an LLM for semantic analysis, but you choose the provider and the endpoint. No data leaves your environment unless you explicitly configure it to. Run it completely air-gapped if you need to.

What languages does Zift support?

Structural scanning (the default pass) covers TypeScript/JavaScript, Java, Python, Go, and C#. Enabling --deep adds Kotlin, Ruby, and PHP through LLM-assisted analysis. Adding new languages is straightforward for contributors since parsers follow a documented pattern in the repo.

Does Zift replace a policy engine like OPA?

No. Zift is a scanner, not a runtime. It identifies authorization decisions in your code and produces Rego scaffolds that give you a starting point for migrating those decisions into OPA. Actual enforcement happens in a policy engine or a platform like EnforceAuth. Zift tells you where you are, and your policy engine gets you where you need to be.

How long does a scan take?

Structural scanning finishes in under a minute for most codebases. Deep mode depends on repository size and which LLM endpoint you connect to, but even large codebases typically finish in under ten minutes. Start structural, get your quick baseline, then decide if you need deeper analysis.

If your externalization percentage is lower than you expected, we should probably talk.

About EnforceAuth

EnforceAuth is the AI Security Fabric for the agentic era. We provide decision-centric authorization across applications, infrastructure, data, and AI workloads. Write policy once. Enforce everywhere.

Follow us on LinkedIn