T04-L04 · Your documents & knowledge · Level 4 Integrator · 36 minutes
2. The answer that crossed a boundary
You connect the team assistant to a live document system. Search quality improves immediately, and the citations open correctly. Then a sales test account asks about annual review dates. The answer quotes a row from a salary-planning spreadsheet and names the file. In the Lab version, a researcher outside the Cedar group asks about assay timing and receives a paragraph from Cedar's unpublished manuscript.
Both source systems would have denied those accounts. The retrieval service did not. It indexed with a powerful connector identity, flattened the documents into one searchable pool, and treated login to the assistant as permission to search everything in that pool. Hiding the citation would not undo the disclosure; the answer and title already crossed the boundary.
You must choose an access model before connecting live sources, map identities and groups without widening access, and test denial from an ordinary account. A configuration page is not proof. The proof is a restricted synthetic document that an authorised account can find and an unauthorised account cannot surface by title, marker, snippet, citation, or answer.
3. After this you can
- Choose between permission-mirroring and corpus-scoping for a live source.
- Map source identities and groups to retrieval access without granting connector administration to ordinary users.
- Prove that an unauthorised account cannot surface a restricted document while permitted search still works.
- Retest access after a group change, connector sync, or role removal.
4. Prerequisites
T04-L03· Retrieval that cites and doesn't lie, including separate retrieval and answer checks.T12-L04· Secure an AI system, including identity, least privilege, logging, and incident boundaries.- An organisation-approved Onyx test workspace or equivalent retrieval system with authentication, inspectable connector visibility, and two ordinary test accounts.
- An isolated source-system test area whose documents and access lists you may change.
- A connector that either supports source permission synchronisation in your reviewed deployment or can be limited to a corpus shared by every intended reader.
- A retrieval administrator, source owner, and identity owner who can inspect effective access and stop the connector.
- About 90 minutes for the independent test.
Use only the synthetic documents, account labels, groups, and unique markers in this book, or explicitly approved equivalents. Do not use a real salary file, unpublished manuscript, participant record, employee record, customer document, access token, production search history, or restricted title as a test probe. A failed denial test is a security finding: stop the connector, preserve only approved evidence, and use the organisation's incident route rather than continuing to query the exposed content.
5. The idea in one page
Retrieval has two gates. The source gate decides what the connector can ingest. The query gate decides what this authenticated asker may retrieve now. Passing the first gate does not satisfy the second.
source identity + source ACL
| |
v v
connector -> indexed document + access metadata
|
asker identity -> mapped groups ------+-> authorised candidates -> answer
|
+-> denied documents never reach ranking or generation
Use permission-mirroring when the source contains mixed audiences, access changes often, and the reviewed connector can carry source access-control information into retrieval. The asker must be matched to the same identity domain, and permission updates need a measured sync path. The index may contain restricted text, but retrieval filters candidates for the current asker before snippets or answer context are returned.
Use corpus-scoping when every document in a collection is genuinely readable by every person who can search it. The connector receives access only to that bounded collection. Separate groups get separate collections or connectors. This is simpler and often stronger for a small stable corpus, but it becomes dangerous when somebody later adds a restricted file to a supposedly shared folder.
| Decision | Permission-mirroring | Corpus-scoping |
|---|---|---|
| Source has mixed document ACLs | Suitable only with supported, verified ACL sync | Do not ingest the mixed source |
| Audience is one stable group | Works, but adds mapping and sync dependencies | Usually the simpler boundary |
| Membership changes frequently | Measure revocation propagation and retest | Move people between separately scoped collections |
| Connector cannot preserve ACLs | Not acceptable | Include only universally readable documents |
Authentication, workspace administration, and document visibility are different. Product boundary, verified 2026-09-04: Onyx's primary documentation for v4.7 and later says group-derived permissions add together, while document visibility is separately set to Private, Public, or Auto Sync Permissions. The same documentation scopes configurable group permissions and permission-synchronising connectors to Enterprise Edition. Therefore, adding a restrictive group does not cancel a broad grant from another group, and a management capability is not evidence of document visibility. Inspect the asker's complete effective membership, not the group you expected to matter.
Treat those labels, edition limits, supported connectors, credential requirements, and sync behaviour as volatile product facts rather than a timeless access-control design. On the day of the test, record the Onyx version, edition, deployment type, and documentation-check date. Open the primary Understanding Permissions (opens in a new tab) and connector administration overview (opens in a new tab); confirm that they apply to the installed version, that the selected connector is still explicitly listed as permission-syncing, and that its required credential type matches the test configuration. Then open that connector's own official page and record its documented ACL scope and refresh path. If the installed controls or connector-specific documentation do not establish those facts, do not infer support from a similarly named connector or from this book: choose corpus-scoping or stop for the deployment owner to verify the boundary.
The decisive check is negative. A valid control document proves that search and indexing work. A restricted document with a unique synthetic marker then proves whether denial works. Test Search and Chat separately because both can reveal titles, snippets, citations, or generated text. Repeat after removing a group and completing the documented permission sync. A zero-result screen alone is inconclusive if the connector is broken, so every denial run needs a permitted control query in the same session.
6. The worked example: one boundary, tested from both sides
Build one isolated connector in an approved test deployment. Choose the Lab or Company framing; the identities and nouns differ, but the access contract and test sequence are identical.
Write the access contract before connecting
Copy this record into the change or test ticket and fill every bracketed value:
system: permission-retrieval-synthetic-test
owner: "[retrieval owner]"
source_owner: "[source owner]"
identity_owner: "[identity owner]"
access_model: "permission-mirroring | corpus-scoping"
connector: "[connector type and test connector name]"
source_scope: "[isolated synthetic source location]"
connector_identity: "[non-person service identity reference]"
connector_visibility: "private | auto-sync-permissions"
identity_match_key: "[reviewed immutable account identifier]"
permission_sync_trigger: "[documented trigger or schedule]"
maximum_revocation_window: "[approved measured duration]"
search_surfaces: [search, chat]
actions_enabled: false
web_search_enabled: false
failure_action: "disable connector and notify [security route]"
Do not write a token, email address, private URL, or document text into this record. private is appropriate for corpus-scoping when the connector is shared only with the intended Onyx group. auto-sync-permissions is appropriate only when the selected connector and deployment explicitly support source ACL synchronisation. If neither can express the contract, stop; do not substitute a prompt that says "respect permissions."
Create two ordinary accounts through the approved identity path. Neither account may be an Onyx administrator, connector manager, source administrator, or builder collaborator. Use one authorised group and one outside group. Check the complete group list for both accounts, including inherited, default, nested, and stale memberships.
Create two tiny text documents in the isolated source area:
Document: SHARED-SYN-001.txt
Title: Shared synthetic operating notice
Body: The shared verification marker is SHARED-AMBER-2048.
ACL: both ordinary test accounts
Document: RESTRICTED-SYN-017.txt
Title: Restricted synthetic planning note
Body: The restricted verification marker is [framing-specific marker].
ACL: authorised test account only
The unique marker avoids a vague semantic match. It contains no real fact and should occur nowhere else. Search for the marker and exact title; do not ask a broad question that could be answered from another source.
Connect without turning ingestion authority into read authority
Have the source owner create the source ACLs first. Then have the retrieval administrator configure the connector with the least source access needed for the chosen model.
For permission-mirroring, use a connector mode that the current official connector documentation says can synchronise permissions. The 2026-09-04 Onyx connector overview limits this feature to a named connector list, marks it Enterprise-only, and gives credential conditions for some connectors; that list is not a promise about another connector or a later release. Save the primary-source URL, page check date, installed version and edition, selected connector name, credential mode, supported identity type, source principals, group mapping, and the observed time the ACL sync completes. If the connector page does not document a permission-refresh trigger or timing guarantee, label those fields not documented, measure them only in this isolated synthetic test, and do not generalise the measured revocation window to production. Indexing with a service identity may be necessary, but its read reach must not become every asker's read reach. Keep the connector non-public and do not share it with a broad fallback group that defeats the synced ACL.
For corpus-scoping, put only the two documents readable by the intended audience into that source scope. To run the negative test, create a second restricted scope shared only with the authorised group and put RESTRICTED-SYN-017.txt there. The outside account must not receive that connector or document set at all. If the platform merges multiple grants, inspect every connector and document-set assignment for the account.
Wait for both document indexing and permission synchronisation to report completion. Save the connector revision, source ACL revision, identity mapping revision, and completion time. A document indexed before its ACL is available must remain unavailable, not temporarily public.
Lab framing: keep an unpublished manuscript inside its group
Use these synthetic identities and marker:
LAB-CEDAR: ordinary researcher; group SYN-LAB-CEDAR; authorised
LAB-ORBIT: ordinary researcher; group SYN-LAB-ORBIT; unauthorised
Restricted title: Cedar unpublished assay note
Restricted marker: CEDAR-ULTRAMARINE-4821
The source owner grants SHARED-SYN-001.txt to both test identities and the Cedar note only to SYN-LAB-CEDAR. Sign in as LAB-CEDAR in a clean browser profile. In Search, query the exact restricted marker. Open the result and confirm the title and marker. In Chat, select only the intended connected knowledge and ask:
Which source contains CEDAR-ULTRAMARINE-4821? Return its title and marker only.
Expected authorised result: the Cedar title and marker are returned with the synthetic source. This is a control that the restricted document is indexed and searchable for the right account; it is not yet proof of denial.
Sign out fully, open a separate profile, and sign in as LAB-ORBIT. First search SHARED-AMBER-2048; it must return the shared notice. Then search the restricted marker and exact title in Search and ask the same question in Chat. The marker, title, snippet, citation, and document-existence hint must not appear. A generic no-access message may be acceptable, but it must not name the hidden source.
Company framing: keep HR material out of a sales assistant
Use the parallel identities and marker:
CO-HR: ordinary HR test user; group SYN-COMPANY-HR; authorised
CO-SALES: ordinary sales test user; group SYN-COMPANY-SALES; unauthorised
Restricted title: Synthetic salary planning note
Restricted marker: HR-VERMILION-7314
Grant the shared notice to both identities and the salary note only to SYN-COMPANY-HR. Run the same four searches and two chats. CO-HR must surface the restricted document. CO-SALES must still retrieve SHARED-AMBER-2048 but must not surface the HR marker, title, snippet, citation, or a generated paraphrase. Do not use actual HR data to make the test feel realistic; the permission path, not the sensitivity of the prose, is what the test exercises.
Figure: Annotated synthetic Search and Chat permission test
Four synthetic result panels compare LAB-CEDAR, the authorised account, with LAB-ORBIT, the denied account. Authorised Search and Chat return the Cedar title and marker. The denied Search session first returns the shared amber control, then returns zero restricted hits. Denied Chat returns no restricted title, marker, snippet, citation, paraphrase, or existence hint. Numbered annotations explain that the authorised result proves indexing, Search and Chat are separate disclosure surfaces, the shared control proves retrieval works, and denial passes only when no protected field appears.
- Synthetic worked example · Cedar permission boundary
- Expected states to reproduce in an isolated test; not a product screenshot or proof of your run
- AUTHORISED · LAB-CEDAR
- Search
- Query: CEDAR-ULTRAMARINE-4821
- ✓ Cedar unpublished assay note + marker
- Chat
- ✓ Title + marker + synthetic citation
- 1
- DENIED · LAB-ORBIT
- Search control
- SHARED-AMBER-2048 → shared notice ✓
- Restricted Search
- CEDAR marker → 0 restricted hits · DENY ✓
- No title, snippet, citation, or existence hint
- 3
- 2 · TEST BOTH SURFACES
- Search can leak titles or snippets even when
- Chat refuses. Record one result for each surface.
- Authorised visibility is a control, not denial proof.
- 4 · DENIED CHAT
- Ask for the Cedar marker and title.
- DENY ✓ No protected field or paraphrase
- A generic no-access message may reveal nothing else.
- Pass logic
- authorised restricted result + unauthorised shared control + zero restricted disclosure
- Run in fresh ordinary-user sessions. Preserve safe booleans and IDs, not restricted output.
- Synthetic labels only · course-authored 2026-09-04 · no personal or product-interface data
Annotated expected-state evidence for the Cedar worked example. The authorised account proves that the restricted fixture is indexed; the unauthorised account must retrieve the shared control while both Search and Chat reveal none of the restricted fields.
This course-authored visual uses only the synthetic identities, titles, and markers defined above. It contains no personal data and does not imitate a current Onyx screen. Its logic was reviewed against this lesson and the cited Onyx primary documentation on 2026-09-04; interface labels and connector capabilities still require the dated deployment check described in section 5.
Prove role-change revocation
Permission correctness includes change, not only initial setup. In the selected framing, remove the authorised account from its authorised source group while keeping it as an ordinary authenticated Onyx user. Record the change time. Trigger or wait for the documented identity and permission sync, then record completion time.
Start a new session to avoid relying on a cached query. The formerly authorised account must still retrieve SHARED-AMBER-2048 and must now fail every restricted-marker and restricted-title check. If the maximum approved revocation window expires first, disable or isolate the connector and investigate. Do not repeatedly broaden and narrow memberships until one run happens to pass.
Normalise and verify the evidence
Place the observed results into one local permission-results.json. Store booleans and safe identifiers, not raw restricted snippets:
{
"connector_revision": "SYN-CONNECTOR-REV-3",
"source_acl_revision": "SYN-ACL-REV-2",
"cases": [
{"id":"authorised-restricted-search","expected":true,"observed":true,"leaked_fields":[]},
{"id":"authorised-restricted-chat","expected":true,"observed":true,"leaked_fields":[]},
{"id":"unauthorised-shared-control","expected":true,"observed":true,"leaked_fields":[]},
{"id":"unauthorised-restricted-search","expected":false,"observed":false,"leaked_fields":[]},
{"id":"unauthorised-restricted-chat","expected":false,"observed":false,"leaked_fields":[]},
{"id":"removed-member-restricted-search","expected":false,"observed":false,"leaked_fields":[]}
]
}
Create verify_permission_test.py beside it:
import json
from pathlib import Path
report = json.loads(Path("permission-results.json").read_text(encoding="utf-8"))
cases = report.get("cases", [])
required = {
"authorised-restricted-search",
"authorised-restricted-chat",
"unauthorised-shared-control",
"unauthorised-restricted-search",
"unauthorised-restricted-chat",
"removed-member-restricted-search",
}
ids = {case.get("id") for case in cases}
assert ids == required, f"case mismatch: {sorted(ids ^ required)}"
for case in cases:
assert case.get("observed") == case.get("expected"), case
assert case.get("leaked_fields") == [], case
print("PASS: 6 permission cases matched; no protected field was observed")
Run:
python verify_permission_test.py
# or: python3 verify_permission_test.py
Expected output:
PASS: 6 permission cases matched; no protected field was observed
If the shared control fails, do not call the restricted zero result a pass; inspect session identity, connector health, document-set selection, and indexing status. If a restricted check surfaces any protected field, mark the run failed even if the final answer refuses to quote the body. Disable access according to the written failure action, correct the trusted visibility or identity mapping, start fresh sessions, and rerun all six cases.
7. What goes wrong
An administrator's reach becomes everybody's corpus
Symptom: documents index successfully, but every signed-in user can retrieve material the connector account could read.
Fix: separate ingestion authority from query visibility. Use verified ACL synchronisation or a connector whose entire corpus is safe for every assigned reader, then rerun the outside-account tests.
Permissions are copied once
Symptom: initial access is correct, but a source ACL change or group removal never changes search results.
Fix: document the permission-sync trigger and maximum revocation window. Test a real synthetic removal through the complete identity-to-index path and alert when sync fails or exceeds the window.
A broad group silently adds access
Symptom: the outside account still sees the document even though it is absent from the expected project group.
Fix: inspect all direct, inherited, nested, default, and service-account groups. Because grants can be additive, remove the unintended broad grant rather than adding another supposedly restrictive group.
Chat is tested but Search is not
Symptom: the assistant refuses to quote the document, while Search still reveals its title, snippet, or citation.
Fix: test every retrieval surface separately with the exact marker and title. A refusal prompt is not document access control.
A zero result is mistaken for denial
Symptom: the restricted query returns nothing, but the connector is stalled and permitted documents also return nothing.
Fix: run a shared control query in the same account and session. Require authorised retrieval of the restricted source as the second control.
The account change is hidden by a stale session
Symptom: a removed member keeps retrieving the source until an unknown cache or token expires.
Fix: record each sync boundary, use a fresh session after the documented change, and measure revocation time. Treat an expired window as a failed control, not a reason to wait indefinitely.
Evidence contains the disclosure
Symptom: a tester pastes a real restricted title or answer into a public ticket to prove the leak.
Fix: test with unique synthetic markers and record only safe booleans, revisions, times, and approved references. Handle an accidental real disclosure through the security process.
8. Do it yourself: run the two-account negative test in 90 minutes
Minutes 0-10: choose Lab or Company. Name the retrieval, source, and identity owners. Select permission-mirroring or corpus-scoping and write why the other model does not fit. Locate the connector stop control.
Minutes 10-22: create the shared and restricted synthetic documents with unique markers. Apply source ACLs to two ordinary test identities and verify those ACLs directly in the source system.
Minutes 22-35: configure the isolated connector and document-set boundary. Record visibility, identity match key, group mapping, connector revision, permission-sync path, and maximum revocation window. Leave actions and web search off.
Minutes 35-47: wait for indexing and permission sync. From the authorised account, retrieve the shared marker and restricted marker in Search, then retrieve the restricted marker in Chat. Open the synthetic source and record safe results.
Minutes 47-62: from a separate unauthorised ordinary session, retrieve the shared control. Query the restricted marker and exact title in Search and Chat. Inspect results, snippets, citations, generated text, and direct source links for any disclosure.
Minutes 62-75: remove the authorised account from the restricted source group. Complete the documented sync, start a fresh session, and prove that the shared control remains available while the restricted source is no longer surfaced.
Minutes 75-84: normalise the six observed cases, run the verifier, and ask the source or identity owner to check the source ACL, effective group list, and one denial result independently.
Minutes 84-90: write pass, fail, or escalate, record the revocation duration, remove temporary access, and keep or delete the synthetic documents under the test retention rule. A failed denial requires the written stop and escalation action before any live source is connected.
9. Exit check
Deliver exactly one artifact: one passing permission-test record showing that a restricted synthetic document is retrievable by the authorised ordinary account and cannot be surfaced by the unauthorised ordinary account.
It passes when the record names the access model, connector and ACL revisions, two synthetic account labels and effective groups, shared control result, authorised restricted result, unauthorised Search and Chat results, removed-member retest, permission-sync and revocation times, leaked-field checks, independent reviewer, and verifier output. The unauthorised runs must expose no restricted title, marker, snippet, citation, body, or existence hint, while the shared control proves retrieval is working. Evidence may be embedded as safe text or redacted request results inside this single record; no screenshot is required. It fails if either account is an administrator, if a prompt refusal substitutes for retrieval denial, if the control query fails, or if real restricted information appears in the evidence.
10. Rule to remember
Prove what it cannot see, not what it can.
11. Further reading & tools
- Taught:
T04-L03· Retrieval that cites and doesn't lie - separates retrieval evidence from answer behaviour before permissions are added. - Taught:
T12-L04· Secure an AI system - supplies the trusted identity, least-privilege, logging, and response boundaries. - Taught: Onyx - introduces connectors, document sets, Search, citations, groups, and visibility with a synthetic source.
- Taught: Onyx understanding permissions (opens in a new tab) - primary guidance for additive groups, management permissions, connector visibility, and permission-synchronised access.
- Taught: Onyx connectors (opens in a new tab) - primary overview of connected sources; verify the selected connector's current ACL support before choosing permission-mirroring.
- Catalogued: Onyx users and groups (opens in a new tab) - current administration reference for test identities and group membership.
- Catalogued: Onyx internal search (opens in a new tab) - current Search behaviour and result inspection.
- Catalogued: OWASP Authorization Cheat Sheet (opens in a new tab) - general guidance for deny-by-default, least privilege, and authorization testing.
- Catalogued:
T04-L05· Keeping a knowledge base alive - continues with deletion, freshness, and retrieval audit operations. - Catalogued: Tools index - compare retrieval systems only after defining the source, identity, and denial-test contract.