Open Policy Agent is the bouncer at the door of your cloud-native infrastructure. It is a general-purpose policy engine that lets you define who can do what, which resources are compliant, and how traffic should be routed — all through code rather than spreadsheets and hope. If you have ever wished for a single tool that could enforce admission control in Kubernetes, authorize API calls, and validate infrastructure-as-code configs, OPA is that tool. It speaks a policy language called Rego, which is declarative, readable, and quietly powerful.
The problem OPA solves is policy chaos. Without it, authorization logic gets scattered across applications, API gateways, CI/CD pipelines, and cluster admission controllers — each with its own format, its own bugs, and its own way of silently doing the wrong thing. OPA consolidates all of that into a single, testable policy layer. The pain that goes away is the pain of inconsistency: rules written once in Rego can be evaluated anywhere, from the API server to the edge proxy to the CI pipeline.
OPA is used by platform engineers, SREs, and security teams who manage multi-tenant Kubernetes clusters, microservice meshes, and compliance-heavy environments. Companies like Netflix, Goldman Sachs, and Atlassian run it in production. It graduated from the CNCF in 2022, meaning it cleared the highest bar for community adoption and project governance.
Version 1.19.0 is worth your attention because it ships a faster, cgo-free WebAssembly runtime, patches a real SQL injection vector in the Compile API, and introduces stricter safety checking for Rego assignments that will catch latent bugs in your policies. It is the kind of release that makes your infrastructure both faster and safer at the same time — a rare and welcome combination.
Think of OPA as the rulebook for your entire stack. This release sharpens the referee.
What Is New in OPA v1.19.0
WebAssembly Runtime Goes Pure-Go With Wazero
The headline feature of this release is the replacement of wasmtime-go with wazero, a pure-Go WebAssembly runtime. This is a bigger deal than it sounds. Previously, if you wanted to run compiled Rego policies as WebAssembly modules — which is how OPA achieves maximum evaluation speed in constrained environments like sidecars and edge proxies — you needed a C toolchain. That meant cross-compilation headaches, larger container images, and build complexity.
With wazero, the cgo dependency is gone. WASM-enabled builds are now pure Go, which means simpler Dockerfiles, smaller images, and easier cross-compilation. On top of that, compiled policy modules are now cached process-wide, so repeated VM creation for the same policy skips recompilation entirely.
The performance numbers are striking. On an Apple M4 Max:
- Cold start (compile + instantiate + first eval): ~73% faster
- Warm evaluation: ~29% faster
- Memory allocations: ~28% fewer
For teams running OPA as a sidecar in every pod or embedding the WASM SDK in latency-sensitive services, these gains compound quickly across a fleet. PR #7557
Stricter Safety Checking for Rego Assignments
The assignment operator := in Rego has always been documented as syntactic sugar for unification with extra checks. But under the hood, := was being treated identically to = (unification), which meant the right-hand side could be made safe by unifying backwards through the left-hand side. That sounds innocuous, but it allowed patterns like this:
x := y
x = 7 # This compiled! y was never defined, but OPA inferred it
Or worse, x := y; obj[x] could silently degrade a constant-time index lookup into full iteration — a performance trap hiding in plain sight. This release makes the right-hand side of := be treated as a read that must be made safe by other expressions, closing the loophole.
Affected policies that relied on the old behavior will now fail with a rego_unsafe_var_error. This is a deliberate semantic change, not a bug fix — the intended behavior of := in these edge cases was never specified. Issue #3546
SQL Injection Fix in the Compile API
This one has a real security impact. The Compile API generates SQL filters from partially evaluated Rego policies. If a policy used a dynamic key like input.fruits[input.column], the caller-controlled text was emitted verbatim into SQL identifiers. That meant a crafted input could transform:
WHERE fruit.name = 'allowed'
into:
WHERE fruit.name = 'allowed' OR 1=1 -- = 'allowed'
Classic SQL injection, hiding inside a policy engine. Field segments that are not bare identifiers are now quoted at the UCAST-to-SQL boundary, with embedded quote characters properly escaped. Ordinary column names stay unquoted, so existing filters keep working and remain case-insensitive on Postgres. PR #8945
Configuration Validation in Rego, With Unknown Option Warnings
Have you ever typoed a config key and spent an hour wondering why OPA was ignoring your settings? This release fixes that. Top-level configuration validation has been rewritten as an embedded Rego policy instead of hand-written Go code, and the immediate user-visible benefit is that unrecognized options now produce a warning at startup:
{"level":"warning","msg":"unknown configuration option "decision_log" encountered"}
These are warnings, not errors — OPA still starts normally. Sections that are intentionally user-extensible are left alone, so extra keys there will not trigger noise. Embedders reading configuration through config.ParseConfig can find the same messages on Config.Warnings. PR #8891
New strings.split_n Built-in Function
Sometimes you only want the first few parts of a split string, and the existing split built-in always returned every part. You had to work around it with wildcards or a slice. The new strings.split_n function takes the first n parts from the front or back:
result := strings.split_n("a.b.c.d", ".", 2)
# result == ["a", "b"]
result := strings.split_n("a.b.c.d", ".", -2)
# result == ["c", "d"]
If abs(n) exceeds the number of parts, all parts are returned. An n of 0 returns an empty array. Small feature, big quality-of-life improvement for policy authors who deal with parsing hostnames, paths, or delimited identifiers. Issue #8344
REPL Line Editing That Does Not Eat Your Pastes
If you have ever pasted a tab-indented snippet into the OPA REPL and watched tab-completion fire on the pasted tab characters — corrupting your input mid-line and producing a spurious parse error — this fix is for you. The old line reader, peterh/liner, had no bracketed-paste support and has been unmaintained since 2021. It has been replaced with reeflective/readline, which properly handles bracketed paste mode.
History files are now persisted as JSON lines instead of one command per line. Existing history files (~/.opa_history by default) are detected and migrated in place the first time the REPL loads them, so you will not lose your command history. Issue #962
Notable Bug Fixes and Improvements
- Go 1.27 support and jsonv2 compatibility added to the AST layer (PR #8947)
- Integer precision loss fixed for integers larger than 64 bits in arithmetic, aggregates, and format_int (PR #8857, Issue #6281)
- SDK deadlock fixed between OPA.Plugin and manager onCommit (Issue #8873)
- Custom HTTP RoundTripper per Decision now supported in the SDK (PR #8884)
- HTTP ReadHeaderTimeout set to 32s on all HTTP servers to prevent slowloris-style resource exhaustion (PR #8877)
- opa build –format flag added for proto/JSON plan bundles (PR #8825)
- Dependency updates including a GHSA advisory fix for oras-go (GHSA-fxhp-mv3v-67qp)
OPA v1.19.0 drops the C toolchain requirement, patches a real SQL injection vector, and makes your policies safer by default — all in one release.



