Skip to content

Security

Not externally audited

connectforge has had internal review only. It handles credentials that can expose a customer's data, so read this page and the technical design before relying on it.

What it protects

A connection is a credential for a customer's account at another service. The module is built so that:

  • the credential is encrypted at rest under a key your key manager holds, bound to its owner, connection and version;
  • a caller never receives the credential: the broker returns an authenticated HTTP client;
  • the credential cannot appear in a record, an event, an error or a log line through the module's own code;
  • a request carrying a credential can reach only the provider's hosts;
  • a record of another tenant is never visible, in code or, with row-level security, in the database.

Defences

Threat Mitigation
Stolen database contents Credentials are ciphertext; additional data binds owner, connection and version, so a ciphertext cannot be moved
Cross-tenant access The owner is in every store method; the conformance suite proves refusal; optional row-level security repeats it in the database
A secret in a log, error or response Secret redacts in every format; provider errors carry a status and a request ID, never a body; a test confines Reveal to the broker and providers
Server-side request forgery through a configurable endpoint Hosts come from the manifest; HTTPS only; no redirect to another host; private, loopback, link-local and shared addresses are refused after DNS resolution
A lost update under concurrency Compare-and-swap on the connection revision and on the credential version
A credential that cannot be read The connection is not used; there is no fallback
An authorization backend outage mistaken for "no" An Authorizer error that is not ErrDenied is reported as a failure

What you must do

  • Supply a real Cryptographer. cryptotest.New() keeps its key in memory and exists for tests.
  • Use a stable, non-reusable owner. An organization ID, not a slug or a name that can be released and given to someone else.
  • Fail closed in the transaction hook when there is no tenant.
  • Keep the egress policy strict in production. AllowPrivate and AllowHTTP exist for tests against local fakes; leave them off.
  • Back up your key material with the database. Without the key, stored credentials cannot be read.
  • Ask providers for the narrowest read permissions their features need, in the manifest's scopes.
  • Treat ErrNotAudited as an incident. The change was made.

Secrets in your own code

  • Hold credentials as connectforge.Secret from the moment you receive them, and never convert to string except at the last moment a provider needs it.
  • Do not log a request body from a provider call.
  • Do not put a credential in a URL, a query string or an error message.

Known limitations

  • Static API tokens only in v0.1.0. OAuth with refresh, GitHub App installations and credential replacement are planned.
  • A client holds the credential it was made with. A disconnect applies to the next client.
  • Grants and bindings are stored but not yet managed by the service; your Authorizer decides.
  • Rate-limit observation, DPoP and agent-delegated authorization are not implemented. The model leaves room for them: a connection is not synonymous with a stored secret.

Reporting a problem

Report a suspected vulnerability privately to the maintainers through the repository's security advisories rather than in a public issue.