Skip to content

Config File Reference

Ghost stores all its settings in a single configuration file written in TOML format — a simple, human-readable format that looks similar to INI files but supports nested sections and typed values. Think of it as Ghost’s “preferences file” — everything from which port the proxy listens on, to your AI provider API key, to whether noise detection is enabled, lives in this one file.

The file is created automatically on first launch with sensible defaults. You can edit it manually with any text editor, but most users change settings through Ghost’s Settings UI, which reads and writes this file through the REST API.


Ghost keeps all its data in a single directory at ~/.ghost/ (your home folder, inside a hidden .ghost folder).

FilePermissionsDescription
~/.ghost/0700 (owner only)The Ghost data directory. Created automatically on first launch. Only your user account can read or enter this directory.
~/.ghost/config.toml0600 (owner read/write only)The main configuration file. Contains encrypted API keys, so it’s restricted to prevent other users on the machine from reading your secrets.
~/.ghost/ca.crt0644 (world readable)The CA certificate that Ghost uses for HTTPS interception. Needs to be readable because it’s installed into browser/OS trust stores.
~/.ghost/ca.key0600 (owner only)The CA private key. This is the most sensitive file — anyone with this key could generate certificates that your machine trusts.
~/.ghost/ghost.dbCreated by SQLiteThe SQLite database containing all captured flows, sessions, findings, conversations, and other persistent data.
~/.ghost/workspaces/<session-id>/0755Per-session workspace directories created for agent file output, containing subdirectories for findings/, scans/, and poc/.

When Ghost saves the config file, it never writes directly to config.toml. Instead, it uses a crash-safe atomic write pattern:

  1. Create a temporary file in the same directory (e.g., .config-abc123.tmp)
  2. Write the TOML-encoded config to the temporary file
  3. Close the temporary file
  4. Set permissions to 0600 on the temporary file
  5. Atomically rename the temporary file to config.toml

If any step fails (disk full, power loss, crash), the original config.toml remains intact. The temporary file is cleaned up on failure. This prevents the nightmare scenario where a half-written config file corrupts your settings.


Controls how the MITM (Man-in-the-Middle) proxy intercepts and processes HTTP/HTTPS traffic.

KeyTypeDefaultDescription
portint4545The TCP port the proxy listens on. Browsers and devices are configured to send their traffic to this port. Changing this requires a restart — it cannot be hot-reloaded.
cert_cache_sizeint10000How many dynamically-generated leaf certificates to keep in memory. Each HTTPS domain Ghost intercepts needs its own certificate, and generating them takes CPU time. The LRU (Least Recently Used) cache keeps the most recently used certificates ready. 10,000 covers most usage patterns. Requires restart to change.
host_includestring[][] (empty = capture all)A whitelist of host patterns. When set, Ghost ONLY captures traffic to hosts matching these patterns. An empty list means “capture everything.” Patterns use glob syntax (e.g., *.example.com matches api.example.com). Hot-reloadable.
host_excludestring[]134 default patternsA blacklist of host patterns to ignore. Traffic to these hosts passes through without being captured or displayed. The defaults cover Windows telemetry, browser telemetry, certificate/OCSP checks, connectivity probes, macOS noise, Edge/Bing, Google services, social media, streaming/media, analytics/ads, CDN infrastructure, and Microsoft services. Hot-reloadable.
upstream_proxystring"" (direct)URL of an upstream proxy to chain through. When set, Ghost forwards traffic through this proxy instead of connecting directly to the internet. Useful in corporate environments with mandatory proxies. Format: http://proxy.corp.com:8080.
ssl_bypass_hostsstring[][] (none)Hosts where Ghost should NOT perform HTTPS interception. Traffic to these hosts is tunneled through as-is, without decryption. Use this for apps with certificate pinning (like banking apps) that would break if Ghost intercepted their HTTPS. Supports wildcard suffix matching (e.g., *.apple.com).
noise_enabledbool*true (when nil)Master switch for noise detection. When enabled, Ghost automatically identifies and suppresses repetitive background traffic (like health checks, polling requests) that clutter the flow list. This is a pointer type — nil in TOML means “use default” which is true.
noise_thresholdint20 (when 0)How many requests from the same pattern within the window before Ghost classifies it as noise. A “pattern” is defined by the combination of HTTP method, host, and URL path. Zero means “use default.” Hot-reloadable.
noise_sample_rateint10 (when 0)Once a pattern is classified as noisy, Ghost keeps 1 out of every N requests (e.g., 10 means keep 10%, discard 90%). This gives you visibility into noisy patterns without flooding the flow list. Zero means “use default.” Hot-reloadable.
noise_window_secsint30 (when 0)The sliding window duration in seconds. Ghost counts how many times a pattern appears within this window to decide if it’s noisy. Zero means “use default.” Hot-reloadable.

Controls the HTTP server that the frontend (and any API clients) connect to.

KeyTypeDefaultDescription
portint5565The TCP port the REST API and WebSocket server listen on. The Ghost frontend connects to this port. Changing this requires a restart.
bearer_tokenstringAuto-generatedThe authentication token for all API access. If empty on first launch, Ghost generates a cryptographically random token (32 random bytes encoded as a 64-character hexadecimal string). This token is never exposed through the Settings API — the frontend receives it via the Tauri sidecar’s startup JSON output.

Controls how Ghost stores captured traffic data in its SQLite database.

KeyTypeDefaultDescription
max_flow_body_sizeint10485760 (10 MB)Maximum size of request/response bodies that Ghost stores inline in the database, in bytes. Bodies larger than this are still captured and forwarded to the browser, but they aren’t saved in the database. This prevents a single large file download from bloating the database. Requires restart to change.
auto_purge_enabledboolfalseWhen enabled, Ghost automatically cleans up old flows on a schedule (every 5 minutes). This keeps the database from growing unbounded during long-running sessions.
auto_purge_max_age_hoursint0 (disabled)Maximum age of flows in hours. When auto-purge runs, any flows older than this are deleted. Set to 0 to disable age-based purging. Only takes effect when auto_purge_enabled is true.
auto_purge_max_flowsint0 (disabled)Maximum total number of flows to keep. When auto-purge runs, the oldest flows beyond this count are deleted. Set to 0 to disable count-based purging. Only takes effect when auto_purge_enabled is true.

Configures which AI model provider Ghost uses for its agent features (test generation, security analysis, traffic understanding, bug reports).

KeyTypeDefaultDescription
providerstring"anthropic"Which AI provider to use. Options: "anthropic" (Claude models), "openai" (GPT models), "ollama" (local models running on your machine).
api_keystring"" (none)Your API key for the selected cloud provider. Encrypted at rest using AES-256-GCM (see Encryption section below). Not needed for Ollama since it runs locally. When displayed in the Settings UI, only the last 4 characters are shown (e.g., ****ab12).
modelstring"" (provider default)The specific model to use. When empty, Ghost uses the provider’s default: Claude Sonnet 4.6 for Anthropic, GPT-4o for OpenAI, llama3.2 for Ollama.
ollama_endpointstring"http://localhost:11434"The URL of your Ollama server. Only relevant when provider is "ollama". The default points to a locally running Ollama instance on its standard port.
KeyTypeDefaultDescription
levelstring"info"Controls how verbose Ghost’s log output is. Options from most to least verbose: "debug" (everything, including individual proxy operations), "info" (normal operations), "warn" (potential problems), "error" (only failures). Requires restart to change.
KeyTypeDefaultDescription
completedboolfalseWhether the user has completed the first-run setup wizard. When false, Ghost shows the setup wizard instead of the main interface. Set to true automatically when the user finishes setup.
proxy_methodstring"" (not chosen)The connection method the user selected during setup: "system_proxy" (Ghost configures the OS to route all traffic through it), "manual" (user configures their browser or device manually), or "device" (user is primarily testing mobile devices).
KeyTypeDefaultDescription
target_hostsstring[][] (scan nothing)Glob patterns defining which hosts the security interceptor should analyze. When empty, passive security scanning is disabled. Example: ["*.hepsiburada.com", "api.example.com"] would scan all hepsiburada.com subdomains and the specific api.example.com host. Hot-reloadable.
disabled_toolsstring[][] (all enabled)Names of security tools the user has toggled off. Ghost’s 8 known security tools (Frida, Nuclei, Dalfox, ffuf, sqlmap, TruffleHog, Katana, Semgrep) are all enabled by default. Adding a tool name here prevents the agent from using it. Hot-reloadable via the Security Tools management UI.

[telemetry] — Error Reporting and Usage Tracking

Section titled “[telemetry] — Error Reporting and Usage Tracking”
KeyTypeDefaultDescription
sentry_dsnstring"" (disabled)Sentry DSN (Data Source Name) for crash and error reporting. When set, unhandled errors are reported to Sentry for debugging. Stripped from settings exports — never shared when you export your config.
telemetry_enabledbool*true (when nil)Whether anonymous usage telemetry is enabled. Ghost sends periodic heartbeats with basic usage statistics (no traffic content, no personal data). This is a pointer type — nil in TOML means “use default” which is true.
telemetry_endpointstring"" (disabled)URL endpoint for telemetry heartbeats. Must be a valid HTTP or HTTPS URL. When empty, heartbeats are not sent regardless of the telemetry_enabled setting.
KeyTypeDefaultDescription
urlstring"" (not configured)URL of your TestRail instance (e.g., https://yourcompany.testrail.io). Must be HTTP or HTTPS. Validated against SSRF (Server-Side Request Forgery) — Ghost refuses to connect to private/local network addresses to prevent the server from being used to scan internal networks.
emailstring""The email address associated with your TestRail account. Used for API authentication.
api_keystring""Your TestRail API key. Encrypted at rest using AES-256-GCM, same as the LLM API key. Masked in the Settings UI (last 4 characters visible). Never included in config exports or imports.

Ghost encrypts sensitive values (LLM API keys and TestRail API keys) at rest using AES-256-GCM — an industry-standard authenticated encryption algorithm. This means even if someone gains access to your config.toml file, they cannot read your API keys without also having access to your specific machine’s identity.

The encryption key is derived from machine-specific values, making the encrypted config file non-portable between machines:

SHA-256("ghost:v1:{hostname}:{os}:{homedir}:ghost-local-encryption-salt")
ComponentSourceFallback
hostnameos.Hostname() — your computer’s network name"unknown-host" if the hostname can’t be determined
osruntime.GOOS — the operating system (e.g., "darwin", "windows", "linux")No fallback (always available)
homediros.UserHomeDir() — your home directory path"unknown-home" if the home directory can’t be determined
SaltFixed string: "ghost-local-encryption-salt"N/A

The SHA-256 hash produces a 32-byte key (256 bits), which is exactly the key size that AES-256 requires.

Safety check: If both hostname AND home directory fail to resolve (both return fallbacks), the key derivation returns an error rather than producing a universal key that would be the same on every machine. At least one machine-specific component must be available.

When Ghost saves an API key:

  1. If the key is empty, store it as empty (nothing to encrypt)
  2. Generate the 32-byte encryption key from machine identity (see above)
  3. Create an AES-256 cipher block
  4. Create a GCM (Galois/Counter Mode) wrapper — this provides both encryption AND integrity verification
  5. Generate a random nonce (one-time number) using crypto/rand — this ensures encrypting the same key twice produces different ciphertext
  6. Encrypt the key and prepend the nonce to the ciphertext
  7. Base64-encode the combined nonce+ciphertext
  8. Store as "enc:" + the base64 string

In the TOML file, encrypted values look like this:

[llm]
api_key = "enc:dGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIGV4YW1wbGU..."

The enc: prefix tells Ghost that this value needs to be decrypted on load. Values without this prefix are treated as plaintext — this enables automatic migration from older configs (see below).

When Ghost loads the config:

  1. If the value is empty or doesn’t start with enc:, return it as-is (plaintext passthrough)
  2. Strip the enc: prefix
  3. Base64-decode the remaining string
  4. Derive the encryption key from machine identity
  5. Split the decoded data into nonce (first N bytes) and ciphertext (remaining bytes)
  6. Decrypt using AES-256-GCM — this also verifies integrity (detects tampering)
  7. If decryption fails (wrong machine, corrupted data): the key is silently cleared to empty string

When Ghost loads a config file and finds a plaintext API key (no enc: prefix), it automatically encrypts and re-saves the config. This is a one-time migration that happens transparently. If the migration save fails, Ghost logs a warning but continues running — the key works fine in memory, it just won’t be encrypted on disk until the next successful save.

What Happens When You Move Configs Between Machines

Section titled “What Happens When You Move Configs Between Machines”

If you copy config.toml to a different computer (different hostname or home directory), the encryption key will be different and the encrypted API keys cannot be decrypted. Ghost handles this gracefully:

  • The API keys are silently cleared to empty strings
  • Ghost continues running normally — everything works except AI features
  • You need to re-enter your API keys in the Settings UI
  • The keys are then encrypted with the new machine’s identity

When you change settings through the Settings UI (or via PUT /api/v1/settings), some settings take effect immediately without restarting Ghost, while others require a restart:

Hot-reloaded immediately (5 subsystems):

SubsystemWhat gets updated
Security interceptorTarget host patterns — which domains get passive security scanning
Proxy host filtersInclude/exclude patterns — which traffic gets captured vs ignored
Noise detectorThreshold, sample rate, window duration — noise detection sensitivity. Existing pattern state (which patterns are currently classified as noisy) is preserved across config changes.
LLM agentProvider, API key, model — creates a new AI provider instance with updated credentials
TestRail clientURL, email, API key — swaps the TestRail HTTP client under a mutex

Requires restart to change:

SettingWhy
proxy.portThe TCP listener is bound once at startup
api.portThe HTTP server listener is bound once at startup
proxy.cert_cache_sizeThe LRU cache is allocated once at startup
store.max_flow_body_sizeUsed during SQLite store initialization
logging.levelThe logger is configured once at startup
api.bearer_tokenOnly changed via the dedicated token rotation endpoint, not the general settings update

The config is managed by a Manager struct that uses a read-write mutex (sync.RWMutex) for thread safety:

  • Reading (Get()): Acquires a read lock and returns a pointer to the current config. Multiple goroutines can read simultaneously. The returned config must NOT be modified — it’s a shared read-only snapshot.
  • Writing (Update()): Applies defaults to fill any zero-valued fields, saves to disk atomically, then acquires a write lock and swaps the config pointer. Until a reader calls Get() again, they continue seeing the old config — this is safe because Go’s garbage collector keeps the old config alive as long as anyone holds a reference.

The API authentication token has its own dedicated rotation mechanism, separate from the general settings update:

  1. POST /api/v1/settings/token/rotate generates a new 32-byte random token
  2. The new token is stored in an atomic.Value (lock-free) for the fastest possible authentication checks
  3. The new token is persisted to config.toml
  4. If the disk write fails, the in-memory token is reverted to the old value — this prevents a situation where the frontend has a new token but it’s lost on restart

[proxy]
port = 4545
cert_cache_size = 10000
host_exclude = ["*.google.com", "*.googleapis.com", "*.gstatic.com"]
ssl_bypass_hosts = ["*.apple.com"]
noise_enabled = true
noise_threshold = 20
[api]
port = 5565
[store]
max_flow_body_size = 10485760
auto_purge_enabled = false
[llm]
provider = "anthropic"
api_key = "enc:dGhpcyBpcyBhIGJhc2U2NC..."
model = "claude-sonnet-4-20250514"
[security]
target_hosts = ["*.hepsiburada.com", "api.example.com"]
[logging]
level = "info"
[telemetry]
telemetry_enabled = true
[testrail]
url = "https://yourcompany.testrail.io"
email = "qa@company.com"
api_key = "enc:YW5vdGhlciBiYXNlNjQgZXhhbXBsZQ..."

When you export your settings (GET /api/v1/settings/export), three sensitive fields are explicitly cleared before the file is generated:

  • llm.api_key — removed entirely
  • testrail.api_key — removed entirely
  • telemetry.sentry_dsn — removed entirely

When you import settings (POST /api/v1/settings/import), Ghost explicitly ignores the llm.api_key and testrail.api_key fields from the imported file. This means importing a config file from another user or machine will never overwrite your API keys — you always need to enter them manually through the Settings UI.