Galley runs locally, but it treats every document and imported project as untrusted input. Security is a first-class concern and is hardened progressively across releases.
Galley is pre-1.0 and under active development. Security fixes target the latest released version.
Please report security issues privately rather than opening a public issue:
- Use GitHub's private vulnerability reporting (Security → Report a vulnerability), or
- email achref.soua@outlook.com.
Include reproduction steps and the affected version. You will receive an acknowledgement, and fixes for confirmed issues will be released and credited (if you wish).
Nothing leaves your machine unless you explicitly enable a cloud AI provider, and then only the data you consent to send. The application has no server, no persistent network connection, and no background daemon.
- Shell-escape is always off. The embedded Tectonic engine does not implement
\write18,\ShellEscape, or\directlua. Shell-escape cannot execute regardless of any flag. CompileRequestcarriesShellEscapePolicy::Offexplicitly; the type system enforces the invariant. The future system-latexmk fallback adapter must honour it with--no-shell-escape.- A pre-compile scanner (
galley-core::sandbox::scan_source) detects all known shell-escape patterns and\input/\includetraversal paths before compilation, surfacing them as UI warnings. The scanner is exposed via thescan_document_sourceTauri command.
- Tectonic's in-process VFS is rooted at the
project_root;\inputresolution is confined to that tree by the engine itself. SafeRoot(galley-security) confines all project reads, writes, and listings to a single canonical project root. Absolute paths,..traversal, and symlinks resolving outside the project are refused.
Archive extraction (.zip / .tar.gz) applies multiple independent guards:
- Null bytes in entry paths are rejected.
- Absolute paths (Unix
/…, Windows\…, drive lettersC:\…) are rejected. ..path components (zip-slip) are rejected.- Symbolic links and hard links are rejected.
- File count, per-file size, and total size limits are enforced via
ArchiveLimits. - All bytes land in memory as
FileEntryvalues before any disk I/O; they are then written throughSafeRoot, which performs a second traversal check on disk.
The import pipeline reads latexmkrc as plain text to extract an engine hint, but never
executes it or any script found in the imported project.
- AI provider keys are stored via
galley-security's file-based secret store at~/.galley/secrets/<provider>with mode0o600, readable only by the owner. - Keys are never written to compile logs, structured logs, error strings, or diagnostic output.
.gitignoreandgitleakspatterns prevent accidental commits.
- The Tauri updater is off by default; the user must explicitly enable it in Settings.
- Update manifests are signed; the updater verifies the signature before applying any binary.
- Until signing certificates are configured, the updater is documented as a no-op.
- Tracked for formal signing setup in v0.7.3 (packaging & signing milestone).
- The Tauri capability configuration grants only
core:default(IPC) anddialog:default(file picker). Nofs,shell,http, or other plugins are enabled. - Every Tauri command is typed and explicitly registered; no
allowlist: all. - CSP is enforced by the OS WebView.
cargo auditandpnpm auditrun as part ofjust ci.- Dependencies are pinned in
Cargo.lockandpnpm-lock.yaml. - SBOM generation:
syft(orcargo cyclonedx) can be run manually and the output attached to release artifacts. - Release artifacts are checksummed (
SHA256SUMS.txt); code signing is wired and documented but awaits signing certificates.
The full threat catalogue, trust boundary diagram, and residual-risk assessment live in
docs/security/threat-model.md. It covers eight threat
categories (T1–T8): shell-escape, input traversal, archive zip-slip, config execution,
secrets in plaintext, malicious update payload, Tauri WebView authority, and cloud LLM
data egress.
The threat model is versioned and reviewed before each beta / release candidate and whenever a new external data path is introduced.