Skip to content

Security: GhostWebEnterprise/ghost-web-ai

Security

SECURITY.md

Security Policy

Supported Versions

Ghost Web AI ships as tagged GitHub releases (vX.Y.Z) with checksummed artifacts and an attached SHA-256 manifest. Only the latest release line receives security updates; older releases are documented for reference only.

Version Supported Notes
0.2.x ✅ Web/desktop updates; future Android releases fail closed (v0.2.3 exception)
0.1.x ❌ Superseded by v0.2.x; no further security updates
< 0.1.0 ❌ Pre-release history, not supported

The latest published release is v0.2.3. Its Android APK was signed with a temporary self-signed RSA-2048 keystore generated on the GitHub Actions runner. The historical run has no downloadable artifact containing that private keystore, so update-signing continuity is not established. Inspection of the historical public Actions log also found that the generated keystore's store and key passwords were printed in plaintext; treat those values as compromised and never reuse them. If a private-keystore backup is recovered outside GitHub, rotate both passwords before placing it in Actions, then verify that its certificate SHA-256 still matches the published v0.2.3 signer. Future Android releases must use the existing signing identity and fail closed if it cannot be reproduced; a replacement key must not be published as an in-place update for the same Android application ID.

Historical signature-evidence limitation: the v0.2.3 workflow made apksigner optional and ran apksigner verify --print-certs through head without pipefail or an explicit verification-result assertion. The original release job therefore did not enforce the verifier's exit status. The exact published APK was independently downloaded and verified on 2026-11-12 by GitHub Actions run #43170557364: the downloaded bytes matched GitHub's asset SHA-256, apksigner verified V1 and V2, exactly one signer was present, and its certificate SHA-256 matched 556745ef7356f3debfac112a66bbfe67d96fcb303c44d1b66d17bd8d5f209006. That audit did not access private signing material and does not establish that the original private keystore can be recovered for future in-place updates.

The audit also recorded 38 unprotected META-INF entries under the V1/JAR signature. The APK declares minSdk 23, so Android API 23 relies on V1 and does not receive V2's whole-APK integrity protection. Android API 24 and later can verify the APK Signature Scheme V2 signature. The release workflow now refuses future Android releases with minSdk below 24 whenever apksigner reports any unprotected META-INF entries; the historical v0.2.3 asset remains published with this limitation documented.

Future releases use the fail-closed verifier and publish its signature report alongside the APK.

This release adds the deployment-wide GITHUB_PAT fallback for repo sync and live publishing (with truthful sync status and actionable 401/403/404 error hints in the UI), a fully responsive mobile/desktop UI, a per-user Settings tab (engine mode, plan-only publishing, repo defaults), iOS/macOS/Linux desktop compatibility shells and desktop installer packaging (macOS .dmg/.zip, Windows .exe, Linux .AppImage/.deb) in the release pipeline, and Ghost Securities © — the background protection engine described below.

Reporting a Vulnerability

Primary channel: email support-ghostweb@proton.me

Please include:

  • Affected version, tag or commit SHA
  • A minimal reproduction (steps, request, or PoC)
  • Impact assessment and any suggested mitigation

What to expect:

  • Acknowledgement within 72 hours of your report
  • Status updates at least every 7 days while a fix is in progress
  • Coordinated disclosure — we ask for up to 90 days before public disclosure while a patch is developed, verified against CI gates (typecheck → tests → build → artifact manifest) and shipped in a new release
  • Credit given in the release notes if you would like to be named

Please do not open a public GitHub issue for unpatched security vulnerabilities, and never attach real credentials or API keys to a report.

Scope

In scope

  • The Ghost Web AI web client (React + TypeScript + Vite)
  • The Convex backend: agent engine, task force, MCP/A2A surface and GitHub OAuth/sync/publish functions (src/convex/**)
  • The Capacitor Android APK shell, the Capacitor iOS shell and the Electron desktop shells and their release-workflow artifacts
  • The release pipeline itself (.github/workflows/), including artifact integrity and checksum verification

Out of scope

  • Vulnerabilities in third-party LLM providers (Anthropic, SambaNova, OpenAI-compatible endpoints) — report those to the provider
  • Issues requiring compromised GitHub accounts, OAuth secrets, or a user's own configured API keys
  • Social engineering of users or hosting infrastructure
  • Automated scanner output without a demonstrated impact

Security controls in this project

  • 🔒 GitHub credentials stay server-side during OAuth flows; access tokens are never sent to the browser.
  • 🛡️ Repository contents are treated as untrusted data, with prompt-injection markers preventing repo text from becoming agent instructions.
  • 🚦 Security and licence checks are blocking gates in the delivery pipeline — nothing ships past them without explicit approval.
  • 🔍 Generated changes receive Guardian review before CI; required CI gates must pass before release/merge readiness.
  • 🧾 Release artifacts are checksum-verified before being attached to a GitHub release (see artifacts.sha256 on each release).
  • ❌ Secrets must never be committed. Provider and OAuth keys are configured through environment variables / project Keys settings only.
  • 🐙 The GITHUB_PAT/GITHUB_TOKEN fallback never leaves the server: sync and publish run as the token's identity server-side, and the UI only ever sees the derived username — never the token itself.
  • 👻 Ghost Securities © runs the background protection engine below on every deployment.

Ghost Securities © — background protection engine

Ghost Securities © is the always-on protection layer that ships with the application and runs in the background on every deployment:

  • Background scans (hourly Convex cron, src/convex/crons.ts → internal.securities.backgroundTick) cover five areas: secrets & credentials, the dependency supply chain (lockfile + GHSA review), code integrity (checksummed artifacts, CI gates, Guardian review), malicious-content / prompt-injection watch, and release hygiene.
  • Verdict model — each scan folds into a single posture: pass, warn or critical. Any critical finding blocks releases until resolved; the posture is visible in-app on the /securities tab.
  • 14-day automatic update cadence — the engine tracks the last automatic-update anchor and re-stamps it every 14 days ("never outdated"): GitHub security-advisory sweep for the locked dependency set, lockfile refresh, a scan for open, useable upstream sources, README/ SECURITY.md sync, and a checksummed maintenance release tag.
  • Protection stack — the standing hardening guarantees are the same controls listed above (server-side secrets, data-not-instructions repo context, blocking gates, Guardian review, checksummed releases), plus the cadence itself.
  • Unit-tested core — the engine is pure TypeScript with zero imports (src/convex/ghost/securities.ts), so the whole defense surface is covered by bun test in tests/securities.test.ts.

The engine currently reports posture from deterministic checks that mirror this policy. Findings that require external reachability (live GHSA queries against the registry) are executed as release-chores each cadence window and must pass before the maintenance release tag moves.

Hardening guidance for deployments

  • Keep GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_PAT/GITHUB_TOKEN and provider keys (ANTHROPIC_API_KEY, SAMBANOVA_API_KEY, OPENAI_API_KEY) out of source and out of the browser bundle.
  • Set SITE_URL to your Convex site URL so the OAuth callback (/github/callback) resolves to your deployment only.
  • The published v0.2.3 APK has GitHub asset SHA-256 88d37d30d236201fb5bb586825a08065f1d067cde8d5cb7d5e679f30641a2e20; its release did not include a separate APK SHA256SUMS asset (the artifacts.sha256 file covers the web build only). For subsequent Android releases, the fail-closed workflow attaches SHA256SUMS and verifies the downloaded APK and manifest bytes before publishing. Android release signing requires all four repository secrets: ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, and ANDROID_KEY_PASSWORD. There is no generated keystore fallback: a missing, invalid, or mismatched keystore blocks the release. To preserve in-place updates from v0.2.3, the signer must match certificate SHA-256 556745ef7356f3debfac112a66bbfe67d96fcb303c44d1b66d17bd8d5f209006. The workflow verifies the APK with apksigner, requires exactly one signer, downloads the published asset again for byte comparison, and removes the temporary keystore after the job.
  • Desktop installers (.dmg/.zip/.exe/.AppImage/.deb) are unsigned by default; verify them against artifacts.sha256 and prefer the checksummed release tag over mirrors. Add code-signing certificates as CI secrets before shipping to end users.
  • The electron/, android/ and ios/ platform shells are scaffolded at build time and never committed — audit the committed capacitor.config.json plus the scaffold workflow instead.
  • Rebuild from a clean checkout and pin the release tag when auditing shipped artifacts.

There aren't any published security advisories