Guerillaglass is an open source desktop project. Please avoid publishing exploit details, bypass techniques, secret values, or proof-of-concept payloads in public issues before maintainers have had time to triage and remediate.
Preferred reporting path:
- Open a GitHub Security Advisory for this repository.
- If advisories are unavailable, open a public issue with a clear
SECURITYprefix, but do not include sensitive details. A maintainer will arrange a private follow-up channel.
Please include, when safe to share privately:
- affected platform: macOS, Windows, Linux, or web
- affected area: desktop bridge, native engine, media/export, executable trust, review bridge, etc.
- reproduction steps
- expected impact
- whether the issue requires local user interaction, renderer compromise, malicious project/media file, or a malicious engine binary
- Acknowledge within 7 days
- Provide a remediation plan or status update within 30 days
- Target fix within 90 days for confirmed issues
High-impact issues affecting arbitrary file write/delete, code execution, executable trust bypass, credential exposure, or unauthorized review mutations may be prioritized faster.
The current hardening work focuses on the desktop app and native engines:
- Electrobun host/renderer bridge boundaries
- local file and media access
- project open/save/export paths
- loopback media serving
- native Swift/Rust sidecars
- executable trust for native engine launch
- macOS code-signature verification helper
- Windows Authenticode verification helper
- local capability tokens for privileged bridge operations
The renderer should be treated as semi-trusted. Host-side validation, grants, rate limits, capability tokens, and native path checks are required even when calls originate from the local app UI.
Desktop signing and executable-trust requirements are also tracked in:
docs/RELEASE_HARDENING.md- Desktop Bun backend configuration uses Effect
ConfigthroughAppConfig. - Runtime composition uses Effect
Layerand a single managed desktop runtime. - Electrobun callback boundaries route work through the managed runtime.
- Sensitive local tokens use
Effect.Redactedwhere applicable.
- Bridge requests have host-side schema validation.
- Bridge requests are guarded by rate limits, concurrency limits, and timeouts.
- Renderer-facing bridge errors are redacted before returning to the renderer.
- New security errors, including capability-token failures, round-trip as typed bridge errors.
Privileged bridge operations are guarded by local opaque capability tokens:
review:mutatemedia:resolve-sourcecapture:resolve-preview-url
Tokens are random, scoped, subject-bound, TTL-bound, idle-expiring, and can be single-use. These tokens are defense-in-depth for local renderer/bridge abuse; they are not a substitute for user authentication or server authorization.
- Path-picker grants are operation-specific.
- Project paths and export paths are validated before native calls.
- Text reads and media snapshots reject symlinks where supported.
- Served media is snapshotted into an app-owned scoped temp directory before loopback serving.
- Rust native writes reject symlink components and non-regular replacement targets.
- Swift native project/export/write paths walk ancestor components with
lstatand reject symlinks. - Swift AVFoundation export writes to a trusted temporary replacement location first, then installs to the final destination with no-follow checks and regular-file-only replacement.
- Existing non-regular export destinations, such as directories named
Reports.mov, are rejected and preserved.
- Media server binds to loopback.
- Media route access is guarded.
- Loopback media URLs are tokenized.
- Media source and capture preview URL minting requires local capabilities.
- Navigation rules are strict.
- Production/stable builds only allow the local packaged main view.
- Dev server navigation is dev-only and tied to configured
PORT. - Trusted local main view remains unsandboxed because Electrobun RPC requires it; host-side bridge validation remains mandatory.
Before launching the configured native engine in production-like mode, the app can enforce:
- no symlink executable
- executable must be a regular file
- reject group/world-writable executable
- optional current-user ownership requirement
- optional SHA-256 allowlist
- optional macOS code-signature requirement verification
- optional Windows Authenticode publisher verification
A Swift helper is included for macOS code-signature verification:
guerillaglass-code-signature-checkerIt uses Apple Security.framework APIs:
SecStaticCodeCreateWithPathSecRequirementCreateWithStringSecStaticCodeCheckValidityWithErrorsSecCodeCopySigningInformation
Production builds should pin a real signing requirement, for example one that includes the expected Team ID and identifier. Release secrets should provide the exact values; they must not be hardcoded into public source unless intentionally public.
Relevant config:
GG_ENGINE_EXPECTED_TEAM_ID
GG_ENGINE_SIGNING_REQUIREMENT
GG_MACOS_CODE_SIGNATURE_HELPER_PATHIf the helper is bundled in the app resources, the desktop backend can auto-discover it. Packaging must ensure the helper is copied before final app signing/notarization.
The Windows native engine includes an Authenticode verification helper mode using Windows trust APIs:
WinVerifyTrustWINTRUST_ACTION_GENERIC_VERIFY_V2- signer certificate extraction
- SHA-256 certificate thumbprint comparison
- publisher subject comparison
Relevant config:
GG_WINDOWS_AUTHENTICODE_HELPER_PATH
GG_WINDOWS_EXPECTED_PUBLISHER_SHA256_THUMBPRINT
GG_WINDOWS_EXPECTED_PUBLISHER_SUBJECT
GG_WINDOWS_ALLOW_OFFLINE_REVOCATIONImportant: a verifier must not rely on an untrusted executable verifying itself. Production Windows packaging should ship or reference an independently trusted/signed helper strategy.
The desktop parity matrix runs automatically on pull requests and pushes to main across:
- macOS
- Windows
- Linux
It covers TypeScript desktop parity plus native smoke/security checks, including:
- Rust workspace tests on Linux/macOS
- Windows native engine check
- Windows Authenticode helper smoke test using a CI-created self-signed code-signing cert
- Swift build/tests on macOS
- macOS code-signature helper smoke test with an ad-hoc signed fixture
The main full gate remains macOS-based and includes formatting, linting, Rust tests, Swift tests, TypeScript tests, docs gate, and coverage threshold checks.
The following are known limitations and should not be treated as completed production guarantees:
-
Production signing values are still required
- real macOS Team ID
- real macOS signing requirement
- real Windows publisher thumbprint/subject
-
Windows Authenticode needs real release validation
- CI uses a self-signed test certificate for behavior coverage.
- Release signing, revocation behavior, and helper packaging must be validated on real Windows release artifacts.
-
Windows helper packaging is not final
- The verifier strategy must avoid circular trust.
- A release build should use a trusted helper or signed packaging layout.
-
AVFoundation is still URL/path-based
- Current export flow is hardened with trusted temp output and no-follow final install.
- True descriptor-backed final media output is not available through high-level AVFoundation APIs.
- Achieving descriptor-perfect output would require a lower-level writer, FFmpeg/libavformat custom IO, GStreamer
fdsink, or similar.
-
Directory-fd traversal would be stronger
- Current Rust/Swift hardening walks path components with
symlink_metadata/lstatand uses no-follow final opens where possible. - A future
openat/directory-fd implementation would reduce remaining check-then-open race windows.
- Current Rust/Swift hardening walks path components with
-
Linux executable trust needs a final policy
- Current trust checks cover generic file properties and optional hashes.
- Linux-specific package/signature/parent-directory trust policy is not finalized.
-
Shared Swift symlink utility should be refactored
- Multiple modules currently implement similar
lstatcomponent walking. - A shared helper would reduce drift.
- Multiple modules currently implement similar
-
Renderer compromise remains in scope for defense-in-depth only
- The bridge is hardened, but a compromised renderer can still attempt allowed local workflows.
- Server-side authorization, Convex auth, and host-side validation must all remain enforced.
When changing desktop or native security-sensitive code:
- Do not add direct desktop backend
process.envreads; useAppConfig/ EffectConfig. - Do not add unmanaged runtime calls in production desktop code; use the managed app runtime or layers.
- Validate all renderer-originated bridge inputs host-side.
- Prefer operation-scoped grants/capabilities for privileged local operations.
- Do not serve arbitrary user paths directly through the media server.
- Do not recursively delete user-selected paths without first checking the node type.
- Reject symlink path components for native writes where possible.
- Keep release signing secrets out of the public repository.