Skip to content

security(kb): the knowledge search and RAG routes filter results by the caller's access #16665

Open

Description

@mrveiss

Parent: #16654. Blocked by the helper-fix sub-issue.

Problem

These routes return knowledge-base facts to the caller without applying ownership or visibility filtering. The evidence is on main at e42be9cb6.

  • api/knowledge_search.py: POST /search (:517). Its reads (:154-159, :179-180, :339-341, :584, :606, :610) apply no quarantine filter either.
  • api/knowledge_search_aggregator.py: /multi-source/search :326, /context :437, /graph :876 and :946. They apply the quarantine filter only.
  • api/knowledge_suggestions.py: POST /suggestions/context (:234 → knowledge/suggestions.py:592).
  • api/knowledge_grounding.py: /ground-response :63 and /verify-claim :142. Both return evidence text.
  • api/knowledge_mcp.py: :446, :574, :635, :685, :1102. Quarantine filter only.
  • api/knowledge_ai_stack.py: :264 and :315.
  • api/ai_stack_integration.py: :105, :195 (prompt) and :269. The router (:65) has no gate, and per-route auth is still to be checked.
  • api/knowledge_rag.py: :132 and :625.
  • api/graph_rag.py: :163.
  • api/kb_librarian.py: :52.
  • api/knowledge_graph_routes.py: :229.

Owner decisions (2026-09-13, on #16654)

These are explicit read APIs, so admins may read any fact through them. SYSTEM facts are visible to every signed-in user.

Acceptance criteria

  • Every route listed above filters its results through the fixed helpers, as the caller.
  • A test per route: user A's PRIVATE fact is not returned to user B, and is returned to A and to an admin.
  • The research quarantine is preserved on every route that has it, and added where a route lacks it.

Refs #16654

Activity

  1. mrveiss commented on Sep 13, 2026

    @mrveiss
    OwnerAuthor

    Found during the #16667 inventory, and in scope here: api/knowledge_mcp.py:466-469 passes filters=request.filters or RESEARCH_QUARANTINE_FILTER, so any filter the caller supplies replaces the research quarantine, and quarantined research facts come back through MCP search. When this route gets its ownership filter, the quarantine must be combined with any caller filter, never replaced by it.

  2. added this to the v0.11.0 milestone on Sep 14, 2026
  3. github-actions commented on Sep 14, 2026

    @github-actions
    Contributor

    PR #16691 (merged to main) references this issue with a close keyword.

    security(kb): the canonical search and multi-source routes filter results by the caller's access (#16665) [1/3]

    If this issue is fully resolved, close it manually. If work remains, no action is needed.

  4. mrveiss commented on Sep 18, 2026

    @mrveiss
    OwnerAuthor

    Progress from PR #16716 (fix at ca12fca46, review pending merge) — partial, not closing.

    Covers 3 of the routes/files listed in this issue's Problem section:

    • api/ai_stack_integration.py: chat and rag_query (:105/:195 region) now filter KB context through filter_search_results_by_permission with the caller's own scope — previously had no filtering at all, gated only by check_admin_permission.
    • api/knowledge_ai_stack.py (:264/:315 region — search/rag_search): the is_admin= bypass keyword removed from the existing filter_search_results_by_permission calls, so an admin caller is filtered identically to any other caller for these RAG-synthesis-bound reads. Same treatment for advanced_search in api/knowledge_rag.py.
    • knowledge_search in ai_stack_integration.py is confirmed correct as an explicit-admin-read route (per the 2026-09-13 owner decision above) and was left untouched.

    Test coverage added per this issue's AC2 for the 3 routes touched: a private fact belonging to user A is not returned to user B or to an admin in the RAG/chat context (verified as a genuine negative control — reverting the fix locally makes these tests fail with the private fact actually present).

    Not covered by #16716, still open per this issue's list: api/knowledge_search.py, api/knowledge_search_aggregator.py (partially covered by a separate PR per earlier review — worth checking before assuming it's fully open), api/knowledge_suggestions.py, api/knowledge_grounding.py, api/knowledge_mcp.py, api/graph_rag.py, api/kb_librarian.py, api/knowledge_graph_routes.py, and the remaining ai_stack_integration.py/knowledge_rag.py line references (:269, :625) not part of this PR's diff.

  5. added 2 commits that reference this issue on Sep 18, 2026
  6. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    Status check against origin/main (1edec3064c): 0 of 3. Five of the eleven named files now filter; six show none at the route or its named service

    #16716 (merged 2026-09-19) covered ai_stack_integration.py and knowledge_ai_stack.py; later commits added filtering in more files. Counted calls to filter_search_results_by_permission / check_access per file named in this issue:

    autobot-backend/api/… calls
    knowledge_search.py 4 filtered
    knowledge_search_aggregator.py 5 filtered
    knowledge_ai_stack.py 2 filtered (#16716)
    ai_stack_integration.py 3 filtered (#16716)
    knowledge_rag.py 2 filtered
    knowledge_suggestions.py 0 its named service knowledge/suggestions.py also has 0
    knowledge_grounding.py 0
    knowledge_mcp.py 0
    graph_rag.py 0 services/graph_rag_service.py also has 0
    kb_librarian.py 0 agents/kb_librarian_agent.py also has 0
    knowledge_graph_routes.py 0

    Scope of this check, stated so it is not over-read: I counted calls to those helpers in each route file and, where the issue names one, its service module. I did not trace every call chain to the bottom. A filter applied deeper (e.g. inside a shared search primitive) would not show up here, so the six zeros mean "no enforcement found at the route or its named service", not "proven unenforced". Criterion 2 (a per-route A/B/admin test) is the check that would settle each one. None of the three criteria can be ticked: criterion 1 is not met for six files, criterion 2 has no per-route tests for them, and criterion 3 was not checked here.

  7. mrveiss commented on Oct 9, 2026

    @mrveiss
    OwnerAuthor

    Sighting (2026-10-09 graph-retrieval sweep): autobot-backend/api/graph_rag.py:172 — the /graph-rag search handler takes current_user for authentication only and never filters results by caller access; services/graph_rag_service.py receives no user. Graph-expanded items here are unfiltered, while api/knowledge_search_aggregator.py:77-145 already applies "a relation is not an access grant". Witness only — the fix stays in this issue. Also a precondition for #18144 (graph view in chat).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions