Zotero 9 cancels HTTP requests carrying an Origin header — BBT endpoints not exempted, breaks Obsidian integration

Author: Geanina-XCreated Sep 14, 2026Updated Sep 14, 2026
Labelsawaiting-user-feedbackquestion

Environment

  • Zotero 9.0.6 (macOS 26)
  • Better BibTeX 9.0.36 (checked: master / 9.0.64 also does not opt in)
  • Obsidian Zotero Integration 3.2.1 (obsidian-zotero-desktop-connector, last release 2024-08)

Problem

Zotero 9's HTTP server cancels any request that carries an Origin header, unless the endpoint sets allowRequestsFromUnsafeWebContent or the request carries zotero-allowed-request / x-zotero-connector-api-version (see Zotero.Server.RequestHandler.prototype._processEndpoint in chrome/content/zotero/xpcom/server/server.js).

BBT's endpoints (/better-bibtex/cayw, /better-bibtex/json-rpc) do not set allowRequestsFromUnsafeWebContent, so every request from Obsidian's Zotero Integration fails with an empty reply, and the plugin reports "Cannot connect to Zotero... Better BibTeX".

Obsidian's plugin sends its requests via Obsidian's requestUrl (Electron main process), which automatically attaches Origin: app://obsidian.md — the plugin cannot suppress this header, and the plugin itself hasn't shipped a release since Aug 2024. This breaks probe, CAYW and JSON-RPC alike, i.e. the entire Obsidian workflow.

Reproduction

bash
$ curl -i 'http://127.0.0.1:23119/better-bibtex/cayw?probe=true' -H 'Origin: app://obsidian.md'
curl: (52) Empty reply from server   # connection cancelled, Zotero.debug logs "Preventing request from browser"

$ curl -i 'http://127.0.0.1:23119/better-bibtex/cayw?probe=true'   # no Origin header
ready

$ curl -i 'http://127.0.0.1:23119/better-bibtex/cayw?probe=true' -H 'Origin: app://obsidian.md' -H 'zotero-allowed-request: true'
ready

Same behavior on /connector/ping, so the guard is at the Zotero server layer, not inside BBT — but BBT is the only endpoint affected tools rely on here, and opting in is a one-liner on BBT's side.

Suggested fix

Set allowRequestsFromUnsafeWebContent = true on the endpoint classes registered in content/cayw.ts and content/json-rpc.ts. Obsidian's requestUrl is an Electron main-process request, not a web-page context, so the threat model the Zotero 9 guard targets (arbitrary web pages probing localhost) does not apply to it.

Current workaround

Patched the Obsidian plugin's shared request-headers constant to include "zotero-allowed-request": "true". Works, but obviously gets overwritten on plugin update, and a proper fix on BBT's side would let users revert.

Source: retorquere/zotero-better-bibtex