onewayglass

Retrieval that cannot tell you what it hid. v0.2.1 · API docs · health

The leak, in one request

No token needed. Counts only, over a corpus of synthetic fiction.

curl "{HOST}/attack?q=compensation+bands+redundancy+acquisition"

The naive counts differ between principals. The enforced counts do not. That difference is the entire result.

Or run it yourself, as two different people

curl -H "Authorization: Bearer demo-u_ic_eng" \
  "{HOST}/search/naive?q=redundancy+planning+next+fiscal+year"
# result_count: 0 of 5 requested. Three restricted documents matched.

curl -H "Authorization: Bearer demo-u_exec" \
  "{HOST}/search/naive?q=redundancy+planning+next+fiscal+year"
# result_count: 5. The difference between these two numbers is the leak.

curl -H "Authorization: Bearer demo-u_ic_eng" \
  "{HOST}/search?q=redundancy+planning+next+fiscal+year"
# result_count: 5. Identical to the CEO's. Content differs; the count does not.

Tokens

Published deliberately — the corpus is fiction and there is nothing to protect. They exist because count-stability is a claim about what different authenticated callers can observe, so it cannot be demonstrated from one anonymous endpoint.

tokenwhodept / levelmay read
demo-u_ic_engEngineerengineering / IC13 of 35
demo-u_lead_engEng Leadengineering / LEAD17 of 35
demo-u_dir_engEng Directorengineering / DIRECTOR20 of 35
demo-u_ic_salesAccount Execsales / IC11 of 35
demo-u_dir_salesSales Directorsales / DIRECTOR15 of 35
demo-u_ic_peoplePeople Partnerpeople / IC10 of 35
demo-u_dir_peoplePeople Directorpeople / DIRECTOR14 of 35
demo-u_execCEOexec / EXEC35 of 35
demo-u_contractorContractorexternal / IC10 of 35

A timing channel survives this

Count-stability is a partial defence. The count channel is closed; a timing channel of about 1.8 µs remains, and the padded arm is faster — so it leaks “this query had few readable matches for you”. Measured at median SNR 0.73 and published rather than buried, because the project’s own thesis committed to that before the code was written.

Endpoints

routeauthwhat
GET /attacknonethe attack across all 9 principals
GET /searchbearerenforced: count-stable
GET /search/naivebearerthe leaking path, deployed unfixed
GET /whoamibearerthis token’s own access
GET /healthnoneasserts count-stability at runtime

Rate limit 120 requests per 60s per token, in-memory and per-instance.