Fascicle is a library that wires LLM calls, tool calls, and subprocesses into
typed workflows. That puts it on the path of API credentials, model output, and
(via the claude_cli provider) a spawned child process, so the security model
below is worth reading before you wire it into anything sensitive.
Please report security issues privately. Do not open a public GitHub issue for a vulnerability.
- Preferred: open a private report through GitHub's security advisories ("Report a vulnerability").
- Alternative: email
hello@robmclarty.comwithfascicle securityin the subject.
Please include a description of the issue, the affected version, and a minimal reproduction if you have one. This is a small, single-maintainer project: expect an initial acknowledgement within a few days, and updates as a fix is worked out. Once a fix ships, credit is given in the release notes unless you ask otherwise.
Fascicle is pre-1.0 and ships breaking changes on minor releases. Only the latest published minor receives security fixes; there is no back-porting to older lines. Pin a version you have reviewed and upgrade deliberately.
| Version | Supported |
|---|---|
latest 0.x minor |
yes |
older 0.x lines |
no |
- The library never reads
process.env. Provider credentials are passed explicitly intocreate_engine({ providers }); reading them from the environment is the harness's job, done at its own boundary. An internal rule (no-process-env-in-core) enforces this acrosssrc/. See docs/configuration.md. - Credentials are not persisted or logged by fascicle. They live only in the engine config you construct and are handed to the underlying provider SDK.
- Trajectory and checkpoint files are sensitive. They capture prompts, model
output, and tool inputs/outputs in plain text. The bundled
filesystem_loggerandfilesystem_storeadapters write unencrypted files to disk; treat their output paths like any other secret-bearing artifact and keep them out of version control.
The claude_cli provider spawns the claude binary and parses its streamed
output. That is a real trust boundary:
- Under
auth_mode: 'oauth'the adapter scrubsANTHROPIC_API_KEYfrom the child environment so a stored session is used instead of leaking a key into the subprocess. Underapi_key/autothe child starts from an empty environment and only caller-supplied values pass through. - fascicle tools that carry an
executeclosure cannot run inside the subprocess. The defaulttool_bridge: 'allowlist_only'only adds tool names to the CLI's own allowlist and silently drops the closures; usetool_bridge: 'forbid'when you need a hard guarantee that noexecuteclosure becomes a silent no-op. - For untrusted work, confine the subprocess with
sandbox: { kind: 'bwrap' | 'greywall', network_allowlist, additional_write_paths }. An emptynetwork_allowlistmeans network-off. Full details in docs/cli.md.
Tools you pass to a model call run in your process, with whatever privileges your process holds. Validate their inputs and scope their side effects; fascicle does not sandbox in-process tool execution.
- Provider SDKs are optional peer dependencies, loaded lazily on first use. Installing fascicle does not pull in eight LLM SDKs; you install only the ones you call.
- A
pnpm auditgate (pnpm check:security,--audit-level=high) tracks known advisories. Transitive advisories are addressed with pinnedoverridesinpnpm-workspace.yaml(for example,smol-tomlandfast-uri).
The following are not fascicle vulnerabilities, though reports that show fascicle mishandling them are welcome:
- Vulnerabilities in a provider SDK, the
claudebinary, or a model endpoint itself. - Secrets leaked by your own harness reading
process.envand logging it. - Prompt-injection of a model you call. fascicle gives you the trajectory as an audit trail; deciding what a tool is allowed to do is your harness's job.