Changes
PR #2261 by ksylvan: fix: harden REST server, template engine and plugins
- Reworked the template engine to resolve each token exactly once in a single linear scan, preventing variable values from being re-expanded into plugin or extension calls and eliminating quadratic processing time on long brace runs.
- Added loopback security middleware and JSON content-type enforcement to the REST and Ollama-compatible servers, so that, when no API key is set, these servers accept only loopback or configured CORS hosts and origins.
- Confined the file plugin to a root directory with
os.Root, rejecting absolute,~,.., and escaping symlink paths, and enforcing read size limits on special files such as/dev/zero. - Restricted the fetch plugin and the Ollama image loader to public network addresses through a shared HTTP client with DNS-level address checks, a 30-second timeout, a 5-redirect limit, and no API key sent to image hosts.
- Added per-session locking with atomic writes, request body size limits (50 MiB), merged
.envupdates, and DOMPurify sanitization plus a Content-Security-Policy in the web UI to prevent data loss, memory exhaustion, and unsafe HTML in rendered output. - Breaking: With no API key, the server gives 403 to a request whose Host is not loopback. To use a LAN address or another host name, add its origin with
--cors-origins. - Breaking: JSON endpoints need
Content-Type: application/json. Other requests get 415. This includes the Ollama-compatible/api/chat: add-H 'Content-Type: application/json'to acurl -dcall. - Breaking: The file plugin reads only relative paths.
- Breaking: The template engine does not expand a variable value again. With
x = "{{name}}",{{x}}gives{{name}}. - Breaking: The fetch plugin and the Ollama image loader ignore
HTTP_PROXY, and they refuse loopback, private and other non-public addresses. This also applies to the CLI. An Ollama image URL on a LAN host now gives an error. - Breaking: Fabric removes terminal control sequences (other than colors) from the CLI output.
GET /configshows a fixed mask in place of each API key. After the upgrade, get the configuration again before you send it toPOST /config/update. The server keeps an old mask, such as****abcd, as a new key value. - Breaking: The Streamlit UI binds to
127.0.0.1. To open it from a different computer, start it with--server.address 0.0.0.0and setFABRIC_UI_TOKEN. - Breaking: In a workflow,
--input-has-varsapplies only to the first input and to each input from the workflow file. The output of a step goes to the next step as literal text. code2contextand the pattern update (-U) skip symbolic links.- New session and context files get mode
0600, and new storage folders get mode0700. Existing files and folders keep their mode. --notification-commandgets the title and the message with no", no'and no\.POST /config/updatemerges into.envand answers 400 for CR, LF or NUL. A strategy name must obey the storage name rules, which refuse Windows device names such asconandauxon all platforms.- Breaking: The REST server runs only the
textanddatetimetemplate plugins in a pattern. Asys,fileorfetchplugin token or an extension token in a pattern gives an error on/patterns/:name/applyand/chat. The CLI runs all plugins. - Breaking: With no API key, the server accepts a
POST,PUT,DELETEorPATCHrequest with anOriginheader only from the same origin (host and port), a--cors-originsentry or a JSON request from the web UI on port 5173 or 4173 (vite preview). Before, it accepted each loopback origin on any port.