Skip to content

fix(desktop): accept self-signed certs from configured external goosed host#8400

Merged
jh-block merged 6 commits into
aaif-goose:mainfrom
Gandalf-Le-Dev:fix/remote-connection-self-signed-cert
Apr 15, 2026
Merged

fix(desktop): accept self-signed certs from configured external goosed host#8400
jh-block merged 6 commits into
aaif-goose:mainfrom
Gandalf-Le-Dev:fix/remote-connection-self-signed-cert

Conversation

@Gandalf-Le-Dev
Copy link
Copy Markdown
Contributor

@Gandalf-Le-Dev Gandalf-Le-Dev commented Apr 8, 2026

Summary

  • The certificate-error and setCertificateVerifyProc handlers in main.ts only accepted self-signed certificates from localhost, rejecting all other hosts
  • This makes remote connection to an external goosed server impossible over HTTPS, since goosed generates a self-signed cert
  • Combined with the CSP blocking plain HTTP to non-localhost hosts, this creates a catch-22 where no protocol works for remote backends
  • Add isTrustedHost() that also trusts the user-configured externalGoosed host, so remote backends work with self-signed certs

Test plan

  • Configure an external goosed server on a remote host with GOOSE_SERVER__SECRET_KEY
  • In Goose Desktop, set remote connection URL to https://<remote-host>:<port> with the secret key
  • Verify connection succeeds (previously failed with "Could not connect to external backend")
  • Verify localhost connections still work as before
  • Verify untrusted hosts are still rejected

fixes #8376

…d host

The certificate-error and setCertificateVerifyProc handlers only accepted
self-signed certificates from localhost, making remote connection to an
external goosed server impossible over HTTPS with its self-signed cert.

Add isTrustedHost() that also trusts the user-configured externalGoosed
host, so remote backends work without requiring a valid CA-signed cert.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b491b7b621

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread ui/desktop/src/main.ts
The original PR (aaif-goose#8400) correctly identified that remote external goosed
connections over HTTPS fail because the certificate handlers reject all
non-localhost hosts. However, simply allowing the external host through
without pinning left TLS validation permanently disabled for that host.

This commit builds on the PR's isTrustedHost() approach but adds
Trust-On-First-Use (TOFU) certificate pinning:

- On the first TLS handshake with a trusted host (local or external),
  the certificate fingerprint is captured and pinned.
- All subsequent connections are validated against that pinned fingerprint,
  preventing MITM attacks after the initial connection.
- The trusted external hostname is cached in memory (updated when a chat
  is created) to avoid synchronous filesystem reads on every TLS handshake.
- The pinned fingerprint resets when a new chat/backend is created so each
  backend gets its own TOFU handshake.

For locally-spawned goosed, the fingerprint from stdout takes precedence
(set after startGoosed returns), matching the existing behavior.

Signed-off-by: jh-block <jhugo@block.xyz>
…ends

Add an optional 'Certificate Fingerprint' field to the external backend
settings UI. When provided, the fingerprint is pinned directly on
connection (skipping TOFU). This lets users who know their server's cert
fingerprint get deterministic pinning without trusting the first
handshake.

Accepts both colon-separated hex (AA:BB:CC:...) and sha256/base64
formats, matching the existing normalizeFingerprint() logic.

Signed-off-by: jh-block <jhugo@block.xyz>
Add GOOSE_TLS_CERT_PATH and GOOSE_TLS_KEY_PATH config options. When both
are set, goosed loads the PEM files instead of generating a self-signed
certificate. The SHA-256 fingerprint is still computed and printed to
stdout for client-side pinning.

Combined with the client-side fingerprint setting added in the previous
commit, this enables a fully deterministic TLS setup for remote backends:
the operator deploys a known cert and the client pins its fingerprint,
eliminating the TOFU trust window entirely.

If only one of the two paths is set, goosed exits with a clear error.

Signed-off-by: jh-block <jhugo@block.xyz>
@jh-block
Copy link
Copy Markdown
Collaborator

I made some changes to tighten this up a bit.

With the local backend we pin the fingerprint to what goosed outputs when it starts up.

With remote backends we can't automatically know the fingerprint of the cert that was generated before connecting, but we now allow the user to specify the fingerprint if known (and I added support on the goosed side for providing a cert + key, so the fingerprint can be known), and if not specified, we do TOFU (pin the fingerprint upon first connect) as a basic protection against MITM during the session.

Signed-off-by: jh-block <jhugo@block.xyz>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b392c54a07

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread ui/desktop/src/main.ts
…Proc

Use callback(-2) (hard failure) instead of callback(-3) (defer to
Chromium default) when a pinned fingerprint doesn't match. With -3,
a CA-valid but fingerprint-mismatched cert (e.g. corporate proxy)
would still be accepted, bypassing both TOFU and explicit pinning.

Signed-off-by: jh-block <jhugo@block.xyz>
@jh-block jh-block added this pull request to the merge queue Apr 15, 2026
Merged via the queue into aaif-goose:main with commit 890ad15 Apr 15, 2026
20 checks passed
jh-block added a commit to sunilkumarvalmiki/goose that referenced this pull request Apr 16, 2026
…l-placeholder

* origin/main: (64 commits)
  fix: expand tool calls by default when Response Style is Detailed (aaif-goose#8478)
  fix: create logs dir before writing llm request log (aaif-goose#8522)
  fix: enable token usage tracking and configurable stream timeout for Ollama provider (aaif-goose#8493)
  fix tauri-plugin-dialog version constraint to match other plugins (aaif-goose#8542)
  call goose serve from tauri frontend via goose-acp client (aaif-goose#8549)
  failed the script when bundle:default fails and cleanup "alpha"  (aaif-goose#8580)
  pass globally unique conversation identifier as sessionId in databricks api call (aaif-goose#8576)
  fix: use sqlx chrono decode for thread timestamps instead of manual parsing (aaif-goose#8575)
  docs: remove stale gemini-acp references (aaif-goose#8572)
  show individual untracked files in git changes widget (aaif-goose#8574)
  fix: update publishing flow to include new sdk dir (aaif-goose#8573)
  fix: remove double border on content in chat (aaif-goose#8545)
  chore(goose2): `just goose2 <command>` with the addition of `just goose2 kill` (aaif-goose#8570)
  Lifei/oltp data (aaif-goose#8458)
  Sidebar polish: search copy, dividers, project reorder, fix DnD (aaif-goose#8568)
  remove the workflow_dispatch check (aaif-goose#8563)
  fix: one more rename (aaif-goose#8562)
  fix(desktop): accept self-signed certs from configured external goosed host (aaif-goose#8400)
  alexhancock/npm-bumps (aaif-goose#8557)
  Remove npm publish from release for now (aaif-goose#8558)
  ...
@Gandalf-Le-Dev
Copy link
Copy Markdown
Contributor Author

nice, thanks for the improvement, do you know when it will release ?

securifera added a commit to securifera/goose that referenced this pull request Apr 29, 2026
…ture

Conflict resolutions:
- configuration.rs: kept both mcp_only (fork) and tls_cert_path/tls_key_path (upstream aaif-goose#8400)
- commands/agent.rs: kept fork's AppState::new(tls, settings) signature + added boot_marker calls from upstream aaif-goose#8656
- state.rs: adopted upstream's OnceLock lazy-init for inference_runtime (aaif-goose#8656) + retained settings: Arc<Settings> from fork
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote connection fails: self-signed cert rejected for non-localhost hosts + CSP blocks plain HTTP

3 participants