惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
Y
Y Combinator Blog
I
InfoQ
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - Franky
IT之家
IT之家
H
Help Net Security
月光博客
月光博客
S
SegmentFault 最新的问题
B
Blog
aimingoo的专栏
aimingoo的专栏
GbyAI
GbyAI
P
Proofpoint News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
G
Google Developers Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
Vercel News
Vercel News
博客园 - 叶小钗
Microsoft Security Blog
Microsoft Security Blog
腾讯CDC
Jina AI
Jina AI
T
The Blog of Author Tim Ferriss

Cerbos - All Posts

Authentik vs Keycloak: Self-hosted IdP comparison Mapping business requirements to authorization policy for automotive Fine-grained authorization for AI gateways EIC 2026: Stop counting agents, protect what they can touch Agent skill for writing authorization policies in Claude Desktop Identity security in 2026 EIC 2026 takeaways: the identity stack built for humans will not hold up for AI agents Already have authentication? Here's the authorization layer you still need. Tokens are authorization decisions: a guide to policy-driven token issuance What is a Runtime Authorization Platform It's a dimmer switch, not a kill switch. How CISOs are rethinking AI agent governance From maps to bitmaps (and from bitmaps to bitmaps) AuthZEN, Shared Signals, SCIM Events, IPSIE: Notes from the OpenID Enterprise Panel How do you update authorization policies without redeploying your application? IIW42 recap: Where agent authorization got real Cerbos PDP v0.52.0/v0.53.0: Engine performance, security hardening, and CEL path functions Authorization Management Platforms: what they do, how they work, and where they fit PocketOS AI coding agent deleted a production database in 9 seconds Non-Human Identity management still has a blind spot Supabase alternative in 2026: Best open source auth options Benefits of on-premise authorization: Why enterprises are moving toward self-hosted Authorization policies: How to write, test, and validate them (faster with AI) Agent skill for writing authorization policies How much does it cost to build authorization in-house? Why centralized authorization governance reduces incident response time OPA alternative Why AI agents make authorization a right now problem Modernizing legacy application authorization: why it’s your biggest security blind spot How to add authorization to legacy applications without code changes 5 authorization blind spots auditors find, and how to fix them
Query plan adapter for LangChain.js and ChromaDB
Alex Olivier · 2026-02-16 · via Cerbos - All Posts

Externalized authorization keeps access control logic out of your application code. You define policies centrally -- who can access what, under which conditions -- and a dedicated engine evaluates them at runtime. With Cerbos, those policies are written as code, stored in version control, and can express roles, attributes, hierarchies, and conditions without requiring application changes.

For traditional database queries, Cerbos offers the PlanResources API: rather than checking each resource individually, Cerbos partially evaluates your policies and returns a query plan -- an abstract syntax tree describing the conditions under which access is granted. Adapters translate that AST into native database filters, so authorization is enforced at the query layer. The database only returns rows the user is allowed to see, and your application never handles unauthorized data.

This same approach applies to vector databases and AI retrieval pipelines. Retrieval-augmented generation (RAG) systems fetch documents based on semantic similarity, but similarity is not authorization. Without filtering, a RAG pipeline can surface confidential data simply because it is semantically close to the question.

Today we are releasing @cerbos/langchain-chromadb, a query plan adapter that translates Cerbos query plans into ChromaDB Where filters. These filters can be passed directly to the LangChain.js Chroma vector store, so authorization is enforced at the retrieval layer -- before any document reaches the LLM.

Why this matters for AI applications

Most RAG implementations have a gap between "what is relevant" and "what the user is allowed to see." The typical workaround is to filter results after retrieval, but that wastes vector search budget on documents that will be thrown away, and risks leaking information through summaries or snippets generated before the filter runs.

By pushing authorization filters into ChromaDB's metadata query, the vector search itself only considers documents the user is permitted to access. No unauthorized document ever reaches the LLM.

How it works

queryPlanToChromaDB takes a Cerbos plan and a field name mapper, and returns a ChromaDB Where filter object.

import { GRPC as Cerbos } from "@cerbos/grpc";
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";
import { queryPlanToChromaDB, PlanKind } from "@cerbos/langchain-chromadb";

const cerbos = new Cerbos("localhost:3592", { tls: false });

const plan = await cerbos.planResources({
  principal: { id: "user1", roles: ["USER"] },
  resource: { kind: "document" },
  action: "view",
});

const result = queryPlanToChromaDB({
  queryPlan: plan,
  fieldNameMapper: {
    "request.resource.attr.department": "department",
    "request.resource.attr.clearance": "clearance_level",
  },
});

if (result.kind === PlanKind.ALWAYS_DENIED) return [];

const chroma = await Chroma.fromExistingCollection(new OpenAIEmbeddings(), {
  collectionName: "internal_docs",
});

const filters =
  result.kind === PlanKind.CONDITIONAL ? result.filters : undefined;

const matches = await chroma.similaritySearch("quarterly revenue", 10, filters);

The mapper translates Cerbos attribute paths (like request.resource.attr.department) to the metadata field names in your ChromaDB collection. It accepts either a plain object or a function for dynamic resolution.

Full example

Consider a policy that restricts document access by department and clearance level:

# policies/document.yaml
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  resource: document
  version: default
  rules:
    - actions: ["view"]
      effect: EFFECT_ALLOW
      roles: ["EMPLOYEE"]
      condition:
        match:
          all:
            of:
              - expr: request.resource.attr.department == request.principal.attr.department
              - expr: request.resource.attr.clearance_level <= request.principal.attr.clearance

When an employee searches for documents, the adapter converts the plan into a ChromaDB metadata filter so the vector search only returns documents the employee is cleared to see:

import { GRPC as Cerbos } from "@cerbos/grpc";
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";
import { queryPlanToChromaDB, PlanKind } from "@cerbos/langchain-chromadb";

const cerbos = new Cerbos("localhost:3592", { tls: false });

async function authorizedSearch(userId: string, question: string) {
  const plan = await cerbos.planResources({
    principal: {
      id: userId,
      roles: ["EMPLOYEE"],
      attr: { department: "engineering", clearance: 3 },
    },
    resource: { kind: "document" },
    action: "view",
  });

  const result = queryPlanToChromaDB({
    queryPlan: plan,
    fieldNameMapper: {
      "request.resource.attr.department": "department",
      "request.resource.attr.clearance_level": "clearance_level",
    },
  });

  if (result.kind === PlanKind.ALWAYS_DENIED) return [];

  const chroma = await Chroma.fromExistingCollection(new OpenAIEmbeddings(), {
    collectionName: "internal_docs",
  });

  const filters =
    result.kind === PlanKind.CONDITIONAL ? result.filters : undefined;

  return await chroma.similaritySearch(question, 10, filters);
}

The filters object passed to similaritySearch might look like:

{
  "$and": [
    { "department": { "$eq": "engineering" } },
    { "clearance_level": { "$lte": 3 } }
  ]
}

ChromaDB applies this filter during the vector search itself, so unauthorized documents are never retrieved or sent to the LLM.

Supported operators

Category Cerbos operators ChromaDB output
Logical and, or $and, $or
Negation not Operator inversion via De Morgan's law
Comparison eq, ne, lt, le, gt, ge $eq, $ne, $lt, $lte, $gt, $gte
Membership in $in

ChromaDB does not natively support $not, so the adapter inverts operators directly: not(eq) becomes $ne, not(and(A, B)) becomes $or[not(A), not(B)] using De Morgan's law, and double negations are eliminated.

ChromaDB stores flat scalar metadata, so string helpers (contains, startsWith, endsWith) and collection operators (exists, all, hasIntersection) are not supported. If a policy emits these operators, the adapter throws a descriptive error.

Get started

npm install @cerbos/langchain-chromadb

The full documentation and source are available on GitHub. If you have questions or run into issues, join the Cerbos community Slack.