Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b2ad445
fix(cors): support trusted reverse proxy origins
goniszewski Sep 22, 2026
c4ebaf5
fix(cors): address reverse proxy origin review feedback
goniszewski Sep 23, 2026
bce077f
Merge pull request #227 from goniszewski/fix/reverse-proxy-origin-val…
goniszewski Sep 23, 2026
d88ea99
chore(release): publish v1.3.0 distribution metadata
goniszewski Sep 28, 2026
5204fe2
Merge pull request #230 from goniszewski/release/v1.3.0-public-metadata
goniszewski Sep 28, 2026
87ff1de
fix(release): satisfy Homebrew formula style
goniszewski Sep 28, 2026
5fc89d3
Merge pull request #231 from goniszewski/fix/v1.3.0-homebrew-style
goniszewski Sep 28, 2026
0613f07
docs(release): record verified v1.3.0 Homebrew upgrade
goniszewski Sep 28, 2026
b68b69a
Merge pull request #232 from goniszewski/docs/v1.3.0-verified-homebrew
goniszewski Sep 28, 2026
376f293
feat(release): use Grimoire archive names after v1.3.0
goniszewski Sep 28, 2026
5b2413c
merge(develop): reconcile release and reverse proxy changes
goniszewski Sep 28, 2026
16e1c50
Merge pull request #233 from goniszewski/chore/future-release-archive…
goniszewski Sep 28, 2026
99de762
fix(security): resolve DNS and block reserved ranges in outbound fetc…
goniszewski Nov 2, 2026
b32ed3d
fix: theme switch and persist theme selection (#236)
hawaka-joe Nov 2, 2026
b8b080e
feat(ai): add Cheaper Inference provider (#235)
aiapienthusiast Nov 2, 2026
2391088
deps: bump fast-uri from 3.1.6 to 3.1.8 (GHSA-58mr-gqgx-xq4g, GHSA-qw…
katsugtgz Nov 2, 2026
17b2b88
chore(deps): update dependencies and fix audit findings (#239)
goniszewski Nov 4, 2026
58004b9
chore(release): prepare v1.3.1 (#240)
goniszewski Nov 6, 2026
18c04ee
test(backup): share Cheaper Inference settings fixture (#242)
goniszewski Nov 6, 2026
07f6ad9
Merge pull request #241 from goniszewski/develop
goniszewski Nov 6, 2026
5da67b0
Merge tag 'v1.3.1' into sync/upstream-v1.3.1
Nov 9, 2026
077fd3e
fix: remediate dependency CVEs reported by Trivy after v1.3.1 sync
Nov 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Guidance for coding agents working in this repository.
- Grimoire is a local-first bookmark manager.
- The frontend is a React 18 + Vite + TypeScript SPA under `src/`.
- The background daemon is a Bun service under `daemon/` that listens on `127.0.0.1:3210`, stores data in SQLite, and exposes the REST API used by the frontend.
- Current published release: `1.2.0`; the next release candidate is `1.3.0`.
- Current published release: `1.3.0`.

## First Reads

Expand Down
40 changes: 28 additions & 12 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ Local integration surfaces such as `/mcp` and `/capture` require a managed beare

## Browser Origin And CORS

Grimoire keeps browser access loopback-only. The daemon trusts the first-party app from `http://127.0.0.1:3210`, `http://localhost:3210`, and configured loopback development origins. Requests without an `Origin` header are treated as non-browser local client traffic and do not receive CORS headers.
Grimoire defaults browser access to loopback origins. The daemon trusts the first-party app from `http://127.0.0.1:3210`, `http://localhost:3210`, configured loopback development origins, and any exact origins explicitly listed in `CORS_ORIGINS`. Requests without an `Origin` header are treated as non-browser local client traffic and do not receive CORS headers.

Configure additional local browser clients with `CORS_ORIGINS` as a comma-separated list of loopback origins:
Configure additional trusted browser clients with `CORS_ORIGINS` as a comma-separated list of exact origins:

```sh
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:4321 littleimpd
CORS_ORIGINS=http://localhost:5173,https://grimoire.example.com littleimpd
```

Only full `http` or `https` origins are accepted, including scheme, host, and any port used by the client. Non-loopback origins are ignored even when configured, unsafe browser writes from rejected origins return `403`, and rejected preflight requests return `403` without reflecting `Access-Control-Allow-Origin`. Protected local capture clients must use loopback origins and a managed integration bearer token.
Only exact `http` or `https` origins are accepted, including scheme, host, and any port used by the client. Explicit non-loopback origins are intended for authenticated reverse proxies or VPNs; paths, credentials, and wildcards are rejected, and the allowlist is not authentication. Unsafe browser writes from rejected origins return `403` with configuration guidance, and rejected preflight requests return `403` without reflecting `Access-Control-Allow-Origin`. Protected capture clients still require a managed integration bearer token.

## Response Conventions

Expand Down Expand Up @@ -1798,7 +1798,7 @@ Request body:
| Field | Type | Required | Description |
|---|---|---:|---|
| `ai` | object | no | |
| `ai.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "none" | no | LLM provider |
| `ai.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "cheaperinference" \| "none" | no | LLM provider |
| `ai.openai` | object | no | |
| `ai.openai.api_key` | string | no | OpenAI API key, empty string clears it |
| `ai.openai.model` | string | no | OpenAI chat model |
Expand All @@ -1821,6 +1821,10 @@ Request body:
| `ai.deepseek.api_key` | string | no | DeepSeek API key, empty string clears it |
| `ai.deepseek.base_url` | string | no | DeepSeek OpenAI-compatible base URL |
| `ai.deepseek.model` | string | no | DeepSeek chat model |
| `ai.cheaperinference` | object | no | |
| `ai.cheaperinference.api_key` | string | no | Cheaper Inference API key, empty string clears it |
| `ai.cheaperinference.base_url` | string | no | Cheaper Inference OpenAI-compatible base URL |
| `ai.cheaperinference.model` | string | no | Cheaper Inference chat model |
| `ai.embeddings` | object | no | |
| `ai.embeddings.provider` | "openai" \| "ollama" \| "openai_compatible" | no | Embedding provider |
| `ai.embeddings.model` | string | no | Embedding model |
Expand Down Expand Up @@ -4234,7 +4238,7 @@ Experimental v0.5 migrate request. Provide dataDir, dbPath, or archivePath.
| Field | Type | Required | Description |
|---|---|---:|---|
| `enabled` | boolean | yes | Whether this runtime feature is usable |
| `provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "none" | yes | Resolved provider |
| `provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "cheaperinference" \| "none" | yes | Resolved provider |
| `model` | string \| null | yes | Resolved model |
| `base_url` | string \| null | yes | Resolved base URL |

Expand All @@ -4253,7 +4257,7 @@ Experimental v0.5 migrate request. Provide dataDir, dbPath, or archivePath.
|---|---|---:|---|
| `llm` | RuntimeLlmCapability | yes | |
| `llm.enabled` | boolean | yes | Whether this runtime feature is usable |
| `llm.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "none" | yes | Resolved provider |
| `llm.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "cheaperinference" \| "none" | yes | Resolved provider |
| `llm.model` | string \| null | yes | Resolved model |
| `llm.base_url` | string \| null | yes | Resolved base URL |
| `embeddings` | RuntimeEmbeddingCapability | yes | |
Expand All @@ -4280,7 +4284,7 @@ Experimental v0.5 migrate request. Provide dataDir, dbPath, or archivePath.
| Field | Type | Required | Description |
|---|---|---:|---|
| `ai` | object | yes | |
| `ai.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "none" | yes | LLM provider |
| `ai.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "cheaperinference" \| "none" | yes | LLM provider |
| `ai.openai` | object | yes | |
| `ai.openai.api_key` | string | yes | Redacted OpenAI API key. Empty string means unset |
| `ai.openai.model` | string | yes | OpenAI chat model |
Expand All @@ -4303,6 +4307,10 @@ Experimental v0.5 migrate request. Provide dataDir, dbPath, or archivePath.
| `ai.deepseek.api_key` | string | yes | Redacted DeepSeek API key. Empty string means unset |
| `ai.deepseek.base_url` | string | yes | DeepSeek OpenAI-compatible base URL |
| `ai.deepseek.model` | string | yes | DeepSeek chat model |
| `ai.cheaperinference` | object | yes | |
| `ai.cheaperinference.api_key` | string | yes | Redacted Cheaper Inference API key. Empty string means unset |
| `ai.cheaperinference.base_url` | string | yes | Cheaper Inference OpenAI-compatible base URL |
| `ai.cheaperinference.model` | string | yes | Cheaper Inference chat model |
| `ai.embeddings` | object | yes | |
| `ai.embeddings.provider` | "openai" \| "ollama" \| "openai_compatible" | yes | Embedding provider |
| `ai.embeddings.model` | string | yes | Embedding model |
Expand Down Expand Up @@ -4333,7 +4341,7 @@ Experimental v0.5 migrate request. Provide dataDir, dbPath, or archivePath.
| `runtime` | RuntimeCapabilities | yes | |
| `runtime.llm` | RuntimeLlmCapability | yes | |
| `runtime.llm.enabled` | boolean | yes | Whether this runtime feature is usable |
| `runtime.llm.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "none" | yes | Resolved provider |
| `runtime.llm.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "cheaperinference" \| "none" | yes | Resolved provider |
| `runtime.llm.model` | string \| null | yes | Resolved model |
| `runtime.llm.base_url` | string \| null | yes | Resolved base URL |
| `runtime.embeddings` | RuntimeEmbeddingCapability | yes | |
Expand All @@ -4352,7 +4360,7 @@ Experimental v0.5 migrate request. Provide dataDir, dbPath, or archivePath.
| Field | Type | Required | Description |
|---|---|---:|---|
| `ai` | object | no | |
| `ai.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "none" | no | LLM provider |
| `ai.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "cheaperinference" \| "none" | no | LLM provider |
| `ai.openai` | object | no | |
| `ai.openai.api_key` | string | no | OpenAI API key, empty string clears it |
| `ai.openai.model` | string | no | OpenAI chat model |
Expand All @@ -4375,6 +4383,10 @@ Experimental v0.5 migrate request. Provide dataDir, dbPath, or archivePath.
| `ai.deepseek.api_key` | string | no | DeepSeek API key, empty string clears it |
| `ai.deepseek.base_url` | string | no | DeepSeek OpenAI-compatible base URL |
| `ai.deepseek.model` | string | no | DeepSeek chat model |
| `ai.cheaperinference` | object | no | |
| `ai.cheaperinference.api_key` | string | no | Cheaper Inference API key, empty string clears it |
| `ai.cheaperinference.base_url` | string | no | Cheaper Inference OpenAI-compatible base URL |
| `ai.cheaperinference.model` | string | no | Cheaper Inference chat model |
| `ai.embeddings` | object | no | |
| `ai.embeddings.provider` | "openai" \| "ollama" \| "openai_compatible" | no | Embedding provider |
| `ai.embeddings.model` | string | no | Embedding model |
Expand Down Expand Up @@ -4411,7 +4423,7 @@ Response data
|---|---|---:|---|
| `data` | Settings | yes | |
| `data.ai` | object | yes | |
| `data.ai.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "none" | yes | LLM provider |
| `data.ai.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "cheaperinference" \| "none" | yes | LLM provider |
| `data.ai.openai` | object | yes | |
| `data.ai.openai.api_key` | string | yes | Redacted OpenAI API key. Empty string means unset |
| `data.ai.openai.model` | string | yes | OpenAI chat model |
Expand All @@ -4434,6 +4446,10 @@ Response data
| `data.ai.deepseek.api_key` | string | yes | Redacted DeepSeek API key. Empty string means unset |
| `data.ai.deepseek.base_url` | string | yes | DeepSeek OpenAI-compatible base URL |
| `data.ai.deepseek.model` | string | yes | DeepSeek chat model |
| `data.ai.cheaperinference` | object | yes | |
| `data.ai.cheaperinference.api_key` | string | yes | Redacted Cheaper Inference API key. Empty string means unset |
| `data.ai.cheaperinference.base_url` | string | yes | Cheaper Inference OpenAI-compatible base URL |
| `data.ai.cheaperinference.model` | string | yes | Cheaper Inference chat model |
| `data.ai.embeddings` | object | yes | |
| `data.ai.embeddings.provider` | "openai" \| "ollama" \| "openai_compatible" | yes | Embedding provider |
| `data.ai.embeddings.model` | string | yes | Embedding model |
Expand Down Expand Up @@ -4464,7 +4480,7 @@ Response data
| `data.runtime` | RuntimeCapabilities | yes | |
| `data.runtime.llm` | RuntimeLlmCapability | yes | |
| `data.runtime.llm.enabled` | boolean | yes | Whether this runtime feature is usable |
| `data.runtime.llm.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "none" | yes | Resolved provider |
| `data.runtime.llm.provider` | "openai" \| "ollama" \| "anthropic" \| "openrouter" \| "openai_compatible" \| "deepseek" \| "cheaperinference" \| "none" | yes | Resolved provider |
| `data.runtime.llm.model` | string \| null | yes | Resolved model |
| `data.runtime.llm.base_url` | string \| null | yes | Resolved base URL |
| `data.runtime.embeddings` | RuntimeEmbeddingCapability | yes | |
Expand Down
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,23 @@ All notable changes to Grimoire will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [1.3.0] - Unreleased
## [1.3.1] - Unreleased

### Added
- Cheaper Inference is available as an AI provider.

### Fixed
- Theme switching works and the selected theme is remembered.
- Grimoire works behind trusted reverse proxy origins.

### Security
- Outbound fetches resolve each hop's hostname and reject private or reserved
addresses, including NAT64, 6to4, and Teredo-embedded IPv6 and internal-only
hostnames.
- Dependencies updated to resolve audit findings, including `fast-uri`
(GHSA-58mr-gqgx-xq4g, GHSA-qw65-cvwx-89v3).

## [1.3.0] - 2026-09-28

### Added
- Later / Revisit rounds present a small shuffled stack of saved bookmarks,
Expand Down
11 changes: 7 additions & 4 deletions Formula/grimoire.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# frozen_string_literal: true

# Install the Grimoire bookmark manager and local daemon.
class Grimoire < Formula
desc "Local-first bookmark manager and search daemon"
homepage "https://github.com/goniszewski/grimoire"
Expand All @@ -6,11 +9,11 @@ class Grimoire < Formula
depends_on "bun"

if OS.mac?
url "https://github.com/goniszewski/grimoire/releases/download/v1.2.0/little-imp-1.2.0-macos.tar.gz"
sha256 "5b99fc6c4d92cd4516b64c1651e847905457775112859eae6bddee40d132635b"
url "https://github.com/goniszewski/grimoire/releases/download/v1.3.0/little-imp-1.3.0-macos.tar.gz"
sha256 "8e87d6631e7ba0bcef91c68a4035b42b7e7eb8c7562791fe3cdd3fd1b9adcf83"
elsif OS.linux?
url "https://github.com/goniszewski/grimoire/releases/download/v1.2.0/little-imp-1.2.0-linux.tar.gz"
sha256 "5217a85217518ccb1e3d2e594b5e85194dccf5fa32ddd673262553f01e70e485"
url "https://github.com/goniszewski/grimoire/releases/download/v1.3.0/little-imp-1.3.0-linux.tar.gz"
sha256 "d12a1e74f75c449a81b9ef0eaa053d1e602a4565cbb6536962962a1da5367c61"
end

def install
Expand Down
14 changes: 9 additions & 5 deletions Formula/release.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
{
"version": "1.2.0",
"version": "1.3.0",
"artifacts": [
{
"platform": "macos",
"archive": "little-imp-1.2.0-macos.tar.gz",
"sha256": "5b99fc6c4d92cd4516b64c1651e847905457775112859eae6bddee40d132635b"
"archive": "little-imp-1.3.0-macos.tar.gz",
"checksum": "little-imp-1.3.0-macos.tar.gz.sha256",
"sha256": "8e87d6631e7ba0bcef91c68a4035b42b7e7eb8c7562791fe3cdd3fd1b9adcf83",
"signature": "little-imp-1.3.0-macos.tar.gz.asc"
},
{
"platform": "linux",
"archive": "little-imp-1.2.0-linux.tar.gz",
"sha256": "5217a85217518ccb1e3d2e594b5e85194dccf5fa32ddd673262553f01e70e485"
"archive": "little-imp-1.3.0-linux.tar.gz",
"checksum": "little-imp-1.3.0-linux.tar.gz.sha256",
"sha256": "d12a1e74f75c449a81b9ef0eaa053d1e602a4565cbb6536962962a1da5367c61",
"signature": "little-imp-1.3.0-linux.tar.gz.asc"
}
]
}
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<br>

[![Quality Gates](https://github.com/goniszewski/grimoire/actions/workflows/quality.yml/badge.svg?branch=main)](https://github.com/goniszewski/grimoire/actions/workflows/quality.yml)
![Release target](https://img.shields.io/badge/release-1.3.0-7c3aed)
![Release target](https://img.shields.io/badge/release-1.3.1-7c3aed)
![Bun 1.x](https://img.shields.io/badge/Bun-1.x-black)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)

Expand Down Expand Up @@ -123,8 +123,8 @@ Open `http://127.0.0.1:3210`.
category/tag management, import/export, backup/restore, diagnostics, and
local update checks.
- Runs without AI providers. Optional providers include OpenAI, Ollama,
Anthropic, OpenRouter, DeepSeek international, and custom OpenAI-compatible
chat or embeddings endpoints.
Anthropic, OpenRouter, DeepSeek international, Cheaper Inference, and custom
OpenAI-compatible chat or embeddings endpoints.

## How It Works

Expand Down Expand Up @@ -187,7 +187,7 @@ cd daemon

### Homebrew

Grimoire v1.2.0 is available through Homebrew. The main Grimoire repository
Grimoire v1.3.0 is available through Homebrew. The main Grimoire repository
serves as the tap; the explicit URL avoids requiring a separate
`homebrew-grimoire` repository. Install it with:

Expand All @@ -206,7 +206,7 @@ kept under `$(brew --prefix)/var/little-imp`; it is separate from the native
`~/.local/share/littleimp` directory and is not migrated automatically.

The public macOS Homebrew path has passed install, service startup, reinstall,
and uninstall checks with data preservation. Upgrading from v1.1 to v1.2 was
and uninstall checks with data preservation. Upgrading from v1.2 to v1.3 was
also validated. Linux Homebrew remains unverified; use the native Linux archive
or Docker Compose there.

Expand Down Expand Up @@ -251,6 +251,7 @@ The daemon reads install-time defaults from `~/.local/share/littleimp/.env`.
| `HOST` | `127.0.0.1` | Bind address. Keep localhost for security. |
| `PORT` | `3210` | Daemon HTTP port. |
| `DATA_DIR` | `~/.local/share/littleimp` | Database, backups, and logs. |
| `CORS_ORIGINS` | local development origins | Comma-separated exact browser origins trusted for writes. Required for an authenticated reverse proxy or a non-default browser-facing port, for example `https://grimoire.example.com`. Paths, credentials, and wildcards are not accepted. |
| `NODE_ENV` | `production` | Use `development` for local development logging. |
| `LOG_FORMAT` | `json` | `json` or `pretty`. |

Expand Down
31 changes: 19 additions & 12 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

| Version | Supported |
| --- | --- |
| `1.3.0` | Yes |
| `1.2.0` | Yes |
| `1.1.0` | Yes |
| `1.0.x` | No |
| `0.1.0-beta` | No |
Expand All @@ -16,9 +18,9 @@ for the repository, that is also an appropriate channel.

Do not report security vulnerabilities through public GitHub issues.

No project-specific PGP key is currently published. If you need encrypted
coordination, ask the maintainer for a preferred secure channel before sharing
sensitive exploit details.
The PGP key attached to GitHub releases verifies release artifacts; it is not
an encrypted-reporting channel. Ask the maintainer for a preferred secure
channel before sharing sensitive exploit details.

Please include:

Expand All @@ -30,14 +32,16 @@ Please include:

## Security Boundary Summary

Grimoire is local-first, single-user, and loopback-first for `1.1.0`.
Grimoire is local-first, single-user, and loopback-first for `1.3.0`.

- Native daemon default: `127.0.0.1:3210`.
- Docker host port default: `127.0.0.1:3210:3210`.
- The first-party browser UI is trusted only from the daemon origin or
configured loopback development origins.
- General REST routes remain loopback-only and tokenless for first-party local
use.
- The first-party browser UI is trusted from the daemon origin, configured
loopback development origins, or exact origins explicitly allowlisted for an
authenticated reverse proxy or VPN.
- General REST routes remain tokenless and are intended only for first-party
loopback use or access through an authenticated proxy or VPN with an exact
configured browser origin.
- MCP and protected local capture endpoints require managed local integration
bearer tokens.
- Public-network exposure is not a supported Grimoire mode. Any remote access
Expand All @@ -48,17 +52,20 @@ Grimoire is local-first, single-user, and loopback-first for `1.1.0`.
an in-browser fixture router, keeps session state in memory, and contains no
server database, secrets, cookies, third-party scripts, or fingerprinting.

Any future non-loopback mode requires a separate security review and explicit
authentication, origin, secrets, and network-exposure controls.
Any broader public or multi-user mode requires a separate security review and
explicit authentication, origin, secrets, and network-exposure controls.

## Implemented Controls

### Network Security

- Localhost-only native binding.
- Loopback-only Docker port publishing.
- Unsafe browser requests are accepted only from configured loopback origins.
- Non-loopback `CORS_ORIGINS` entries are ignored by the daemon.
- Unsafe browser requests are accepted only from default loopback origins or
exact origins explicitly configured with `CORS_ORIGINS`.
- Explicit non-loopback origins are intended only for authenticated reverse
proxies or VPNs. Wildcard origins are not accepted, and the origin allowlist
is not a substitute for authentication.
- Private, loopback, link-local, and unspecified hosts are blocked for bookmark
fetching and update-source handling where route behavior requires public
targets.
Expand Down
Loading
Loading