<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Syed Muzakkir Hussain</title>
    <description>The latest articles on DEV Community by Syed Muzakkir Hussain (@muzakkirhussain011).</description>
    <link>https://dev.to/muzakkirhussain011</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4187022%2Fa9dc1561-2fd9-4501-aea7-b86ee6bbc41f.png</url>
      <title>DEV Community: Syed Muzakkir Hussain</title>
      <link>https://dev.to/muzakkirhussain011</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/muzakkirhussain011"/>
    <language>en</language>
    <item>
      <title>Make your AI assistant answer only from what each person may see</title>
      <dc:creator>Syed Muzakkir Hussain</dc:creator>
      <pubDate>Sun, 25 Oct 2026 01:49:39 +0000</pubDate>
      <link>https://dev.to/muzakkirhussain011/make-your-ai-assistant-answer-only-from-what-each-person-may-see-44p5</link>
      <guid>https://dev.to/muzakkirhussain011/make-your-ai-assistant-answer-only-from-what-each-person-may-see-44p5</guid>
      <description>&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/1239159340" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;An AI assistant answers from documents it finds by search, and that search ranks chunks by how similar they are to the question. It does not know who is asking. So whenever documents with different readers share one index, the closest match to a question can be something the person asking was never allowed to see, and the assistant quotes it back.&lt;/p&gt;

&lt;p&gt;The same leak shows up wherever privacy matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SaaS apps:&lt;/strong&gt; someone at one customer asks when their contract renews and gets another customer's contract terms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Healthcare:&lt;/strong&gt; a question from the front desk pulls in a patient's diagnosis that only the care team may read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Banking:&lt;/strong&gt; an analyst on one side of an information barrier gets a summary of a deal they are walled off from.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inside a company:&lt;/strong&gt; an engineer asks about pay and the assistant summarises HR's salary bands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI agents:&lt;/strong&gt; an agent that searches with a shared service account can read everything, whoever it is working for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OWASP lists this in its Top 10 for LLM applications as &lt;a href="https://genai.owasp.org/llmrisk/llm082025-vector-and-embedding-weaknesses/" rel="noopener noreferrer"&gt;LLM08:2025 Vector and Embedding Weaknesses&lt;/a&gt;: context leaking between users or tenants that share one vector database. The first fix it lists is fine-grained access control with permission-aware vector and embedding stores.&lt;/p&gt;

&lt;h2&gt;
  
  
  What wardowl does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/muzakkirhussain011/wardowl" rel="noopener noreferrer"&gt;wardowl&lt;/a&gt; is an open-source Python library (MIT) that makes retrieval permission-aware, with the vector store and the permission system you already run. Every search runs as the person asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It filters inside the search.&lt;/strong&gt; When your permission system can describe everything a user may read, wardowl turns that into a filter in the vector store's own query, so the results are the true top-k of what that user may read, not the top-k of everything with the forbidden ones removed afterwards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It checks every hit again.&lt;/strong&gt; Pre-filtered results are re-checked, so a backend bug that ignores the filter cannot leak, and each result reports how many such violations it caught.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It fails closed.&lt;/strong&gt; If the permission service errors, times out or answers nonsense, the user gets an error, never unfiltered results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For agents, wardowl's MCP server takes the user from the verified access token on every request, so the model never chooses whose permissions it searches with.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few lines of Python
&lt;/h2&gt;

&lt;p&gt;This is the first case above, two companies sharing one assistant. The other cases use the same code; what changes is where the permissions come from, such as care-team relationships in OpenFGA or SpiceDB, deal teams in your policy engine, or groups from your identity provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;wardowl&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InMemoryBackend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MetadataACLAuthorizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PermissionedRetriever&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;backend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InMemoryBackend&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contoso-order-form&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Contoso contract renewal: June 30, at list price.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allowed_groups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contoso&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}),&lt;/span&gt;
    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;northwind-msa&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Northwind contract renewal: March 1, 3 years, 18% off.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allowed_groups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;northwind&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}),&lt;/span&gt;
    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pricing-policy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Renewal pricing policy for every customer.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allowed_groups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;retriever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PermissionedRetriever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MetadataACLAuthorizer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bob&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contoso&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;retriever&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contract renewal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;# ['contoso-order-form', 'pricing-policy']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Northwind's agreement never reaches the prompt, however similar it is. In production you swap the in-memory store for yours and the metadata check for your permission system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Works with what you have
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vector stores:&lt;/strong&gt; pgvector, Qdrant, Milvus, MongoDB Atlas, Weaviate, Redis, LanceDB, FAISS, Vespa, Cassandra, Pinecone, Elasticsearch, OpenSearch and Chroma.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission systems:&lt;/strong&gt; OpenFGA, SpiceDB, Open Policy Agent, Cerbos, Cedar, Casbin and Ory Keto, or access lists in metadata, or your own rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frameworks and services:&lt;/strong&gt; LangChain, LlamaIndex, Haystack, an MCP server for agents, and an HTTP service for any language.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tested the way a company would use it
&lt;/h2&gt;

&lt;p&gt;The acceptance suite runs one assistant shared by two companies, each with HR, finance, engineering, legal and board documents, and people in different roles, from an HR manager to a contractor. It runs on 14 stores and seven permission systems, against real servers, a real identity provider and real embedding models, and checks every outcome against an independent list of who may read what: 3,912 checks in all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;wardowl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/muzakkirhussain011/wardowl" rel="noopener noreferrer"&gt;https://github.com/muzakkirhussain011/wardowl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://muzakkirhussain011.github.io/wardowl/" rel="noopener noreferrer"&gt;https://muzakkirhussain011.github.io/wardowl/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions and feedback are welcome in the comments or on GitHub.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>security</category>
      <category>python</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
