Skip to content

VAP15-53 docs(server-url): document credential withholding on caller-supplied server urls - #1221

Draft
jeffrey-hoekman-vapi wants to merge 1 commit into
mainfrom
jeffhoekman/vap15-53-webhook-credentials-withheld-caller-supplied-server-url
Draft

jeffrey-hoekman-vapi wants to merge 1 commit into
mainfrom
jeffhoekman/vap15-53-webhook-credentials-withheld-caller-supplied-server-url

Conversation

@jeffrey-hoekman-vapi

Copy link
Copy Markdown

Linear ticket

VAP15-53 — https://linear.app/vapi/issue/VAP15-53

Value

V.A.L.U.E. tier: micro — docs-only, one file, no blast-radius path.

VAPSEC-564/619/623 changed a documented contract: when a server URL arrives in the request itself — a transient assistant, or assistantOverrides — Vapi no longer attaches the org's webhook credential, and credential fields in the payload arrive as "[REDACTED]". The docs still promised the old behavior, so a customer hitting this sees an unauthenticated webhook and no explanation — indistinguishable from a broken listener.

Affects: orgs on the caller-supplied server-URL path (97 in the VAPSEC-564 cohort), plus every org created after the VAPSEC-689 cutoff. Secondarily CS and FDE, who field the "my webhook stopped authenticating" ticket.

What changed

All in fern/server-url/server-authentication.mdx:

  1. A Quick start warning. The "Test your webhook" step promised "Vapi will now authenticate requests to your webhook using the configured credential" unconditionally. The condition now travels with the promise, where a reader meets it, rather than 300 lines later.
  2. A ### When credentials are not attached section — which paths are caller-authored, the explicit contrast that saved assistants / phone numbers / tools keep their credentials, and the [REDACTED] payload note.
  3. #### Confirming a withheld send in your logs — what support actually needs: the literal log string, the suppressed high-volume message types, and the trap that a missing log entry does not mean credentials were sent.
  4. A rollout qualifier (see blocker below).

Why the rollout qualifier is here

Without it the page states the withholding unconditionally, while pre-cutoff orgs are still gated by ENABLE_WEBHOOK_CREDENTIAL_BINDING. An unenrolled org could read "no X-Vapi-Secret header" and conclude its org secret is not reaching a third-party URL — when it still is. That is an inaccuracy in the unsafe direction, so the qualifier is not optional polish.

It deliberately does not tell a pre-cutoff org when their turn comes. The ramp is a hand-maintained override list with a limited number of slots, mostly already allocated; an invitation to request enrollment would be a promise we cannot service.

🚫 Blocker — do not merge as-is

The rollout qualifier contains the literal placeholder ENFORCEMENT_DATE_TBD. The VAPSEC-689 cutoff (WEBHOOK_CREDENTIAL_BINDING_CUTOFF, currently defaulting to 2026-10-01T00:00:00.000Z in https://github.com/VapiAI/vapi/pull/19995) is still being settled with the CISO, infosec, and the EM. An MDX comment at the insertion point marks it.

Everything except that one token is ready for review now.

Merge gate

  • VAPSEC-564/619/623 have deployed. The original gate is satisfied.
  • Publish before the VAPSEC-689 cutoff instant, not merely "around the same time as VAPSEC-689". Enforcement for new orgs begins at the cutoff, which is by construction later than that PR's deploy. From that moment every brand-new org gets this behavior during onboarding — and unlike the migration cohort, a brand-new org cannot be warned in advance and has no CS relationship yet. This page is the only explanation it will ever get. Landing early is harmless: it describes behavior already true for the enrolled cohort, now correctly qualified. If the cutoff date moves, this deadline moves with it.
  • Accurate for both populations: the ENABLE_WEBHOOK_CREDENTIAL_BINDING cohort, and — from the cutoff onward — unconditionally every newly created org.

Follow-on obligations

Trigger Action
VAPSEC-689 cutoff date moves This page hardcodes the date; it needs a docs PR. Recorded on VAPSEC-689.
VAPSEC-654 deletes the flag, ramp at 100 The rollout qualifier becomes false and must be removed. Recorded on VAPSEC-654.
VAPSEC-627 ships Subsystem server URLs (tools, KB, custom voice, handoff/transfer destinations, endpointing) — VAP15-54, stacked on this branch, still provisional.

Evidence

Check Result
fern check 0 errors, 12 warnings (pre-existing OpenAPI discriminator warnings, untouched by this PR)
Prose verified against serverUrlFunctions.ts, serverMessageUtil.ts, serverUrlFunctions.secretBinding.spec.ts, sessionFunctions.secretBinding.spec.ts

Out of scope

The message-options override paths (handoff-destination-request, tools, KB, custom voice, endpointing) belong to VAPSEC-627 and are tracked in VAP15-54. Documenting them here would publish behavior that is not yet true and would disclose an open finding.

Refs VAPSEC-564, VAPSEC-619, VAPSEC-623, VAPSEC-689.

🤖 Generated with Claude Code

…supplied server urls

Org webhook credentials are attached only when the server URL comes from
org configuration. When it arrives in the request itself - a transient
assistant or assistantOverrides - Vapi sends the webhook without the org
credential, and credential fields in the payload read [REDACTED].

Adds a Quick start warning so the unconditional "Vapi will now
authenticate requests" promise carries its condition, and a
"When credentials are not attached" section with the log-entry detail
support needs: the literal string, the suppressed high-volume message
types, and the trap that a missing entry does not mean credentials were
sent.

Scoped to VAPSEC-564/619/623. The message-options override paths
(handoff-destination-request, tools, KB, custom voice) are VAPSEC-627 and
are documented separately once that ships.

Refs VAP15-53
@github-actions

Copy link
Copy Markdown
Contributor

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.

1 participant