Security
This page covers how Conduit protects vendor credentials, how it defends against prompt injection attacks, how multi-tenant and subtenant isolation are enforced, and what security properties you should understand when deploying Conduit for your MSP.
Credential Security
Section titled “Credential Security”Encryption at Rest
Section titled “Encryption at Rest”All vendor credentials stored in Conduit are encrypted using AES-256-GCM with per-record key derivation. The key derivation uses PBKDF2-SHA512 with 100,000 iterations, seeded with a per-record 32-byte salt and a scope-binding string (user, team, or organization identifier). This means:
- Each credential record’s encryption key is derived independently — compromising one record’s derived key gives no information about any other record.
- Credentials encrypted for one scope cannot be decrypted using another scope’s context.
- A database breach exposes ciphertext, not plaintext credentials.
Encryption is performed at the application layer before credentials reach the database. The database stores only encrypted blobs.
The reference implementation is a small, self-contained module (~100 lines). The cipher, KDF, and parameter sizes are byte-for-byte identical to the WYRE MCP Gateway. We’re happy to walk through it on a call.
Credential Resolution Hierarchy
Section titled “Credential Resolution Hierarchy”Conduit resolves vendor credentials in the following order:
- Personal credential — stored on the requesting user’s account.
- Team-bound named org key — if any of the user’s teams has a named org key configured for the vendor. Checked across all of the user’s teams at once; if more than one team has a matching key, the alphabetically-first key name wins deterministically (no ambiguity fallback).
- Legacy team credential — if the user is a member of exactly one team that has the older-style team credential configured, and no named org key matched above. Multi-team ambiguity here (the user is in two teams that both have a legacy credential for the vendor) falls through to the org-level step rather than picking one arbitrarily. Being phased out in favor of the named-org-key model above; the read path and its OAuth-refresh write-back stay until a later removal, not yet dropped.
- Organization credential — resolved in two sub-steps: (a) the org’s own default credential, then (b) a reseller-shared vendor grant pointing at the reseller’s credential. When a reseller-shared grant is used, the resolution is recorded in the audit log.
- 403 Forbidden if no credential is found at any scope.
This hierarchy lets MSPs centralize shared vendor accounts at the org level (or share credentials downstream from a reseller to a sub-customer) while allowing individual technicians to override with personal credentials when needed.
The reference implementation is documented inline in the credential-injection module.
Credential Injection
Section titled “Credential Injection”Vendor credentials are never transmitted to the AI model or the end-user’s local workstation. The flow:
- The AI client (in the user’s MCP client) calls a tool — for example,
autotask__list_tickets. - Conduit receives the call, authenticates the request, and decrypts the relevant credentials for that user (resolved per the hierarchy above).
- Conduit makes the upstream API call to the vendor using the decrypted credentials.
- The upstream response is returned to the AI client.
At no point do credentials leave Conduit’s server-side environment. The MCP protocol carries only the tool name, arguments, and result — not credentials.
Vendor OAuth Tokens
Section titled “Vendor OAuth Tokens”For vendors that use browser-based OAuth (Xero, QuickBooks Online, Calendly), Conduit stores the OAuth access token and refresh token — encrypted using the same per-record AES-256-GCM scheme. Token refresh is handled automatically when access tokens expire.
Network and egress
Section titled “Network and egress”Conduit’s outbound vendor API calls leave from one static egress IP, 20.242.40.128. Allowlist that address when a vendor firewall or API key restricts source IPs — IT Glue API keys and on-prem ConnectWise Automate are the common cases. This is the address those outbound calls leave from. It is not an address your AI client connects to.
If you would rather not open firewall access to an on-prem system, use a tunnel. The address, where to enter it, and the related connect guides are on Static egress IP.
Trust Model
Section titled “Trust Model”This section answers the question sophisticated buyers ask: “If the operator of Conduit gets compromised, what’s my exposure?” It’s the right question and we want to answer it precisely.
The honest version
Section titled “The honest version”Conduit decrypts secrets in-process to proxy your API calls — that means whoever operates the deployment (you, if self-hosted; WYRE, if WYRE-managed) holds the trust dependency. With production access plus a database export, an operator could in principle decrypt customer credentials offline. This is a property of any vendor that handles your secrets to make API calls on your behalf — Conduit is in that category, as is every alternative tool that handles credentials.
We will not claim otherwise.
What matters is whether that trust dependency is bounded, observable, and reversible.
Bounded — the blast radius
Section titled “Bounded — the blast radius”- Per-record key derivation means an attacker with master key + database has to do per-record cryptographic work for every credential they want to decrypt. There is no free mass dump.
- There is no admin “view credential” page, no support-tier reset path, and no export script in the codebase. Adding one would require new code visible in git history.
- Postgres Row-Level Security (RLS) is enabled across tenant tables (see Multi-Tenant Isolation). RLS predicates are written as
SECURITY DEFINERhelper functions to avoid recursive evaluation and to make policy intent reviewable.
Observable — the audit trail
Section titled “Observable — the audit trail”- Every tool call appears in the audit log within seconds.
- Every infrastructure-level access (secret read, database query) is logged in your cloud provider’s activity logs (retention varies by provider — see your provider’s documentation).
- Every code change to credential-handling paths goes through code review.
Reversible — the kill switch
Section titled “Reversible — the kill switch”- Rotate the credential at the vendor (ConnectWise, Autotask, etc.) at any time and what Conduit holds goes stale instantly. Conduit holds no persistent vendor sessions.
- Delete the credential from Conduit and the encrypted record is erased immediately.
- Remove a member from your org and their access to org credentials is gone with no cached tokens.
- Remove a sub-organization from a parent reseller and the subtenant relationship is severed (see Subtenant Model).
What we’re working on
Section titled “What we’re working on”The single biggest improvement to this trust model is envelope encryption with a cloud-managed HSM-backed key encryption key (KEK) that has wrapKey/unwrapKey permission only — no extract permission, even for operators. After that change ships, a person with full subscription RBAC can call online decryption (with audit trail) but cannot extract the key for offline mass decryption. This moves the trust boundary from “people with prod access” to “code running in the operator’s managed identity context.”
The design and migration plan for this change is in flight.
What we won’t claim
Section titled “What we won’t claim”- “Staff cannot decrypt your data.” Not true today.
- “Hardware-secured master key.” Not true today. The master key is in a cloud secret, not a hardware module. It moves to HSM-backed KEK with the envelope-encryption work above.
- “Zero-knowledge service.” Not true and not architecturally possible for a credential proxy.
- “SOC 2 / ISO 27001 / CMMC certified.” Not certified. We’ll claim it when we earn it.
How to verify what we say
Section titled “How to verify what we say”- Run a tool call and verify it appears in your audit log within seconds.
- Rotate a credential at the vendor side and observe Conduit’s tool calls fail with the expected upstream auth error.
- Delete a credential and verify it is no longer reachable.
- Ask for a code walkthrough —
src/credentials/crypto.tsis ~100 lines and explains itself. - Read our trust center — the live view of our compliance posture, monitored controls, and subprocessors, published continuously by Vanta rather than written by us.
- Running a vendor security review? The security page is the procurement-facing version of this document, including a filterable due-diligence answer bank.
Authentication
Section titled “Authentication”User Authentication (Auth0 OIDC)
Section titled “User Authentication (Auth0 OIDC)”Conduit users authenticate via Auth0 OIDC. Users sign in with their email; migrated WYRE MCP Gateway users sign in with the same email and are matched to their account automatically.
MCP Client Authentication (OAuth 2.1 + PKCE)
Section titled “MCP Client Authentication (OAuth 2.1 + PKCE)”MCP clients (Claude Desktop, Claude Code, third-party MCP clients) authenticate to Conduit via OAuth 2.1 with PKCE (Proof Key for Code Exchange):
- The MCP client generates a random
code_verifierand derives acode_challengeusing SHA-256 (S256 method — plaintext challenge is not accepted). - The user is redirected to Conduit’s authorization endpoint, including the
code_challenge. - The user completes authentication via Auth0.
- Conduit returns an
authorization_codeto the MCP client. - The MCP client exchanges the
authorization_codefor tokens by sending thecode_verifierto the token endpoint — proving it is the same client that initiated the flow. - Conduit issues a JWT access token and a refresh token.
Conduit publishes OAuth 2.1 metadata at /.well-known/oauth-authorization-server in compliance with RFC 8414.
JWT Access Tokens
Section titled “JWT Access Tokens”Access tokens are HS256-signed JWTs with a configurable TTL. The token includes the user’s identity and organization context. Expired tokens are rejected; MCP clients automatically use the refresh token to obtain a new access token without requiring re-authorization.
Refresh Token Rotation
Section titled “Refresh Token Rotation”Each time a refresh token is used, Conduit issues a new refresh token and invalidates the old one. This rotation pattern means:
- Stolen refresh tokens have a narrow window of usefulness before they are cycled out.
- Concurrent use of the same refresh token (e.g., if a token was intercepted and used by an attacker) is detectable — if the original client and the attacker both try to use it, one will fail with an invalid token error.
Invitation Token Hashing
Section titled “Invitation Token Hashing”Organization invitation tokens are stored as hashes, not plaintext. Acceptance and creation paths are rate-limited (10/hr for creation, 5/15min for acceptance) to defeat brute-force enumeration.
Multi-Tenant Isolation
Section titled “Multi-Tenant Isolation”Database-Level Isolation (RLS)
Section titled “Database-Level Isolation (RLS)”Every record in Conduit is scoped to an organization ID (org_id). Postgres Row-Level Security (RLS) is enforced on tenant tables. RLS predicates are written as SECURITY DEFINER helper functions to:
- Avoid recursive policy evaluation that could pessimize query plans.
- Centralize tenant-context logic in named functions, making policy intent reviewable.
WITH CHECK clauses on INSERT and UPDATE policies prevent cross-tenant writes.
An authenticated user from Organization A cannot retrieve credentials, audit logs, or member information belonging to Organization B — the RLS predicate is evaluated by Postgres for every query, regardless of how the query is constructed at the application layer.
Credential Namespace Isolation
Section titled “Credential Namespace Isolation”Credentials stored by one organization are encrypted using that organization’s scope-bound derived keys. Even if two organizations’ encrypted blobs were somehow co-mingled, they would be encrypted under different keys and would not be decryptable across organizations.
Subtenant Model
Section titled “Subtenant Model”Conduit supports a reseller hierarchy: an MSP (the reseller) may have multiple sub-organizations (their customers), each of which may itself have sub-organizations. The hierarchy is bounded to depth 3.
A reseller administrator can administer their direct customers and (transitively) their customers’ sub-organizations. A customer administrator can administer only their own organization and direct sub-organizations.
Reseller-level pricing configuration is scoped to the reseller and not visible to sub-customers.
Vendor API Isolation
Section titled “Vendor API Isolation”When Conduit makes upstream API calls, it uses credentials resolved from the requesting user’s organization context. Conduit does not share vendor credentials across organizations.
Container Architecture
Section titled “Container Architecture”Vendor MCP server containers run on an internal network and are not directly exposed to the public internet. All inbound traffic passes through Conduit’s authentication and authorization layer before reaching vendor MCP servers. The mechanism varies by deployment topology — docker-compose deployments use container expose: (internal-only) rather than ports: (host-bound), and the managed cloud deployment runs vendor containers as internal services reachable only through the gateway, with managed ingress fronting the single public endpoint.
Prompt Injection Defense
Section titled “Prompt Injection Defense”The Threat
Section titled “The Threat”Prompt injection is a class of attack in which malicious instructions are embedded in data returned to the LLM via a tool call — for example, in a ticket subject line, a document body, or an API response field — with the intent of hijacking the model’s behavior. In an MSP context this could take the form of:
- A ticket created by an external party with a subject line containing instructions to exfiltrate other ticket data.
- A document in IT Glue containing hidden instructions to retrieve password records.
- An email subject line instructing the model to perform actions on behalf of the attacker.
Conduit-Level Defenses
Section titled “Conduit-Level Defenses”Conduit implements structural defenses against prompt injection at the tool response layer:
Response envelope isolation. Tool responses are returned to the MCP client as structured tool_result objects, not as raw text injected into the conversation. This structural separation makes it harder for injected text to be interpreted as top-level instructions, because the model receives it as data-typed content, not conversation flow.
Tool result content type tagging. Responses are tagged with their content type (structured data vs. text), giving the model context about the nature of what it is reading.
Privileged tool separation. Tools that access sensitive credential stores (password retrieval in IT Glue, Hudu, etc.) are namespaced and can be restricted to specific roles via tool allowlists. Restricting access to credential retrieval tools reduces the blast radius of a successful injection that attempts to exfiltrate passwords.
Defensive Practices for MSP Teams
Section titled “Defensive Practices for MSP Teams”- Restrict credential-access tools. Use tool allowlists to limit which roles can call password and credential retrieval tools.
- Apply least privilege. Each team member should only reach the tools they need for their role.
- Monitor anomalous patterns. Periodically review the audit log for unusual tool usage sequences.
Threat Scanning
Section titled “Threat Scanning”Threat scanning is an observation-mode detection layer a reseller admin can turn on for a customer org — the customer cannot enable it themselves, and it is off by default. It watches for two signals:
- Agent-identity drift — the same credential suddenly presenting from a different client shape, a signal of a stolen credential in use.
- Provenance tracking — untrusted content from an earlier tool response reappearing in the arguments of a later, sensitive call, a signal of indirect prompt injection or data exfiltration.
What it inspects — and what it cannot see
Section titled “What it inspects — and what it cannot see”Conduit is a terminating proxy: to route any tool call it already holds that call’s arguments and the vendor’s response in memory. Threat scanning reads that same in-flight data — it adds no new visibility beyond what the gateway already processes to do its job — and it is deliberately narrow:
- It does not see your prompts or your AI conversation. Conduit receives tool calls, not the chat between you and your model. What you typed, the model’s reasoning, and any message that never became a tool call are never visible to Conduit at all — with or without threat scanning.
- Agent-identity drift reads only connection metadata — the credential source, OAuth client,
User-Agent, and endpoint — hashed into a fingerprint. It reads none of your business data. - Provenance tracking inspects tool traffic but keeps only token shapes. From “untrusted-source” reads (web fetches; reads of email / ticket / note / document / message content) it extracts a few high-signal token shapes — email addresses, URLs, and long opaque identifiers — into a small, in-memory, per-session set, then checks whether any reappear in a later sensitive (“sink”) call’s arguments. It does not copy your records; free-form prose that isn’t one of those shapes is not retained even in memory. The scan is bounded (≤256 KB per call, and it fails open — a scanner problem never affects your call), and the in-memory set is per-process and lost on restart. None of it is ever written to disk.
What it retains
Section titled “What it retains”Detection happens in memory; storage is metadata-only. Nothing the scanner persists contains your content:
- Aggregate counts — per org / day / detector / severity, plus a “calls scanned” denominator. Numbers only.
- Per-detection metadata — on a detection only (clean traffic leaves nothing): one row holding the severity, detector, the vendor/tool involved, the source→sink shape, the argument path that tripped (e.g.
$.to— the field name, never its value), which principal, an occurrence count, and a reference to the standard request log. It stores none of: the flagged value, the extracted token, your call arguments, or the response.
This is enforced at the write path, not just promised: evidence fields are allowlisted (a new detector fails closed rather than accidentally logging something sensitive), and the dedup key — which embeds the flagged token — is SHA-256 hashed before storage, so the value cannot be recovered from the row. The “Request” reference points at Conduit’s normal request log, which follows its own existing retention (13 months) and redaction rules; the detection row itself carries no payload.
Enablement, mode, and where it shows up
Section titled “Enablement, mode, and where it shows up”Today this is observation only: it blocks nothing — every detection is recorded in monitor mode and the tool call proceeds normally. Once enabled, the org’s admin sees a Threat scanning section on their Overview page — Calls Scanned (30d), Threats Detected (30d), Highest Severity, and a detector breakdown table — with honest empty states while scanning is clean or still gathering data. A View all detections link opens /org/security, a per-event drill-down grouped by triage state: severity, detector, what tripped, actor, occurrence count, last-seen time, the underlying request log reference, plus status (Open / Acknowledged / Resolved) and an optional owner (org member). Observation mode stays labeled — assigning a finding does not block the tool call. For reseller admins, the reseller’s own Overview additionally shows an aggregate Customer threat scanning view across every enabled customer org — orgs monitored, calls scanned, and threats detected, plus a per-customer breakdown row.
None of this alerts or notifies — admins have to check the Overview or Security page to see it, so treat it as observation infrastructure rather than an actionable alerting tool.
Billing & Payment Security
Section titled “Billing & Payment Security”Stripe Integration
Section titled “Stripe Integration”Subscription billing is handled by Stripe. Conduit never stores card data; it stores only the Stripe customer ID and subscription state.
Webhook Verification
Section titled “Webhook Verification”Stripe webhooks are verified via the Stripe-provided HMAC signature on every request. Webhook handlers return a non-2xx status on processing failure so Stripe will retry — this prevents silent loss of subscription state changes.
Dunning Lifecycle
Section titled “Dunning Lifecycle”Subscription failures (failed renewals, expired cards) move the org through a dunning lifecycle with a configurable grace window before service is gated. The grace window defaults to 7 days and is configurable via the WYRE_DUNNING_GRACE_DAYS environment variable. The first-failure timestamp is persisted so the lifecycle is recoverable across service restarts.
During the grace window, customers retain access. After the grace window expires, plan-gated features are disabled at the service layer using the isPaidPlan helper, ensuring consistent behavior across all enforcement points.
Audit Logging
Section titled “Audit Logging”Every tool call made through Conduit is recorded in the request log. Log entries are immutable — they cannot be modified or deleted by users. Each entry records:
- User identifier
- Organization identifier
- Tool called (vendor + tool name)
- Timestamp (UTC)
- HTTP response status
- Request duration
Administrative actions (team membership changes, credential updates, allowlist modifications, invitation sends, impersonation events) are separately recorded in the admin_audit_log table with the acting user and timestamp.
Admin audit log records are append-only and kept indefinitely — no code path can modify or delete them. A database trigger unconditionally rejects every UPDATE and DELETE against admin_audit_log, by deliberate design: an earlier age-gated deletion option was rejected as a documented, undetectable way to destroy old evidence.
Owners and admins can export logs as CSV from the dashboard.
Security Recommendations
Section titled “Security Recommendations”For new organizations:
- Set default server access to
noneand explicitly grant vendor access via teams. This gives you a deny-by-default posture. - Configure tool allowlists for the member role to restrict sensitive operations (credential retrieval, delete operations).
- Create service accounts for automated workflows instead of sharing user credentials.
For established organizations:
- Review admin audit logs monthly to confirm no unauthorized configuration changes have occurred.
- Rotate service account secrets on a scheduled basis (quarterly recommended).
- Remove deprovisioned employees from the organization promptly — an off-boarded employee’s access persists until explicitly revoked.
For organizations in regulated industries:
- Export audit logs to your SIEM or long-term storage on a scheduled basis — Conduit’s retention may not satisfy your regulatory retention requirements.
- Configure tool allowlists to prevent credential access tools from being called in automated workflows where they are not needed.
Frequently asked questions
Section titled “Frequently asked questions”How are my vendor credentials protected?
Section titled “How are my vendor credentials protected?”All vendor credentials are encrypted with AES-256-GCM using per-record key derivation, at the application layer before they reach the database, so a database breach exposes ciphertext rather than plaintext. Credentials are never sent to the AI model or the user’s workstation — Conduit decrypts them server-side only to make the upstream vendor call.
If whoever operates Conduit is compromised, what is my exposure?
Section titled “If whoever operates Conduit is compromised, what is my exposure?”Conduit decrypts secrets in-process to proxy your API calls, so the operator of the deployment — you if self-hosted, WYRE if WYRE-managed — holds the trust dependency. With production access plus a database export, an operator could in principle decrypt credentials offline, as is true of any tool that handles your secrets to make API calls on your behalf. What makes that dependency bounded, observable, and reversible is detailed in the Trust Model section above.
Can Conduit staff read my credentials, and is Conduit certified?
Section titled “Can Conduit staff read my credentials, and is Conduit certified?”We will not claim that staff cannot decrypt your data, that the master key is hardware-secured, that Conduit is zero-knowledge, or that it is SOC 2 / ISO 27001 / CMMC certified — none of those are true today. The master key currently lives in a cloud secret; moving it to an HSM-backed key with no extract permission, via envelope encryption, is the planned next step.
How does Conduit keep one organization’s data isolated from another?
Section titled “How does Conduit keep one organization’s data isolated from another?”Every record is scoped to an organization ID and protected by Postgres Row-Level Security, which is evaluated for every query regardless of how it is constructed, so a user from one organization cannot retrieve another’s credentials, audit logs, or members. Credentials are additionally encrypted under organization-scoped derived keys, so blobs are not decryptable across organizations.
How does Conduit defend against prompt injection?
Section titled “How does Conduit defend against prompt injection?”Conduit returns tool responses as structured tool_result objects rather than raw text, tags responses by content type, and namespaces privileged credential-retrieval tools so they can be restricted by role through tool allowlists — all of which reduce the blast radius of an injection. MSP teams should pair these with least-privilege allowlists and periodic audit-log review.
Does Conduit detect anomalous or malicious activity?
Section titled “Does Conduit detect anomalous or malicious activity?”A reseller admin can opt a customer org into threat scanning, an observation-mode layer that watches for stolen-credential signals (a credential suddenly presenting from a different client shape) and indirect-injection/exfiltration signals (untrusted content resurfacing in a later sensitive call). It blocks nothing today, but once enabled the org admin can see what it’s catching on their Overview page, and drill into each individual detection — severity, detector, what tripped, actor, occurrence count, triage status, and owner — on a dedicated Security page, metadata only, never the flagged content itself. The customer still cannot turn it on themselves; that stays reseller-controlled.

