Security & Technical Design — Cody Zoom Meetbot
Effective Date: 2026-05-15 Last Updated: 2026-05-15
Cody Zoom Meetbot ("Cody," "the App," "we," "us," or "our") is a Zoom Marketplace application operated by Obsidian Inc., d/b/a Lattice. Cody joins authorized Zoom meetings as an AI assistant to provide real-time transcription, conversational Q&A, action-item extraction, and post-meeting summaries.
This document accompanies the Cody Privacy Policy and Terms of Service. Where the Privacy Policy describes what data we collect and why, this document describes how the system is built, how that data is protected end-to-end, and what controls govern access. It is intended for Zoom Marketplace reviewers, security-conscious customers, and anyone evaluating Cody against their own information-security requirements.
This Security & Technical Design is published at https://codewarrior4life.github.io/lattice-meetbot-public/security.html and is referenced from the Cody Zoom Meetbot Marketplace listing per Zoom's Marketplace requirements.
1. Overview
This document covers the design of Cody as it pertains to the security, privacy, and integrity of user data obtained through the Zoom Marketplace OAuth grant and through the Zoom Meeting SDK. Specifically, it describes:
- The runtime architecture and its ephemerality guarantees
- How Cody authenticates to Zoom and how it is authorized to act on a user's behalf
- The OAuth scopes Cody requests and why each is necessary
- The data flows through the system, from authorization through meeting end through deletion
- Encryption in transit and at rest
- Storage, retention, and revocation
- Tenant isolation and access control
- The subprocessors Cody relies on and what each is allowed to see
- Our secure development lifecycle and supply-chain transparency
- Vulnerability disclosure and incident response
- Our compliance posture, including where we are explicitly not yet certified
Where this document is silent on a control, the corresponding statement in the Privacy Policy governs. Where the two documents speak to the same control, the more restrictive of the two governs.
2. Architecture at a glance
Cody is built on a single architectural axiom: one container per meeting.
For every Zoom meeting Cody is authorized to join, the App spawns a fresh, ephemeral Linux Docker container. That container is the entire trust boundary for the meeting. It exists from the moment the meeting begins (or from the moment the host admits Cody from the waiting room) until the meeting ends or Cody is removed. When the container terminates, all in-memory state — audio buffers, decoded PCM frames, transient transcripts, chat context windows, LLM prompts — is destroyed with it. Any artifact that must outlive the meeting (the meeting WAV recording, the final transcript, the generated summary) is written to encrypted storage governed by the retention rules in §7 of this document, and the container itself is torn down.
There is no long-running multi-tenant daemon, no shared in-memory state across meetings, and no co-located processing of two meetings inside the same process. This is a deliberate failure-isolation and blast-radius decision: if a container is compromised, the only data exposed is the data for the single meeting that container was processing.
The major components inside each meeting container are:
- The Zoom Meeting SDK for Linux (v7.0.x), which authenticates to Zoom signaling, joins the meeting as a real participant ("Cody Assistant (Notetaker)"), and exposes meeting events, chat messages, and raw PCM audio frames to the App.
- A FastAPI runtime sidecar, which orchestrates the SDK lifecycle, fans audio frames out to the transcription path, brokers chat messages to and from the LLM, and exposes a small HTTP/WebSocket surface for the consuming orchestrator to monitor the meeting in real time.
- A transcription pipeline, which either streams audio to Deepgram for low-latency Speech-to-Text (when that subprocessor is enabled) or runs a local Whisper backend inside the container if Deepgram is disabled.
- An LLM client that calls Anthropic's Claude API for in-meeting
@codyreplies and for the post-meeting summary.
The bot is a real meeting participant. It is not a screen-scraping browser hack. It does not animate a Chromium window or read pixels off a video frame. Audio is delivered by the SDK's audio-helper callback path as raw PCM. Video frames are not subscribed to at all, which is enforced by the SDK initialization config rather than by a downstream filter — the bytes are never delivered to the App.
3. Authentication and authorization
Cody uses a dual-credential authentication model. Two distinct credentials must be present for the bot to join a meeting, and they serve different purposes.
3.1 Meeting SDK Key/Secret → SDK JWT
The first credential is the Meeting SDK Key/Secret issued to Obsidian Inc. as the developer of Cody. At container startup, the SDK Key/Secret is loaded from the container's secret store and used to mint an HS256 JWT. The JWT is passed to SDKAuth(ctx), which authenticates the SDK client process to Zoom's signaling infrastructure.
This credential identifies the application to Zoom. It is owned by Obsidian, rotated on a periodic schedule, and is never exposed to end users, displayed in product UI, or written into logs.
3.2 End-user OAuth grant → access token, refresh token, ZAK
The second credential is the end-user OAuth grant. When a Zoom user authorizes Cody through the Marketplace, Zoom issues an OAuth access token and a refresh token scoped to the permissions the user granted (see §4). For each meeting Cody is asked to join on that user's behalf, the App exchanges those tokens for a short-lived ZAK (Zoom Access Key) token, which lets the SDK present itself in the meeting as the authorizing user's notetaker rather than as an anonymous third party.
This credential identifies the user to Zoom. Refresh tokens are stored encrypted at rest (see §6), are rotated according to Zoom's policy, and are deleted within 30 days of authorization revocation, as described in §7.
The dual-credential model means that neither the SDK Key alone nor a stolen access token alone is sufficient to join a meeting in a way that impersonates a user: the SDK Key authenticates the app, the OAuth grant + ZAK identifies the user, and both are required to produce a valid SDK join payload.
4. OAuth scopes and justifications
Cody requests the minimum set of OAuth scopes required to deliver its features. We do not request, and the App does not exercise, any *:write scope. Cody does not modify Zoom account settings, does not create or schedule meetings, does not change passwords, does not invite participants, and does not delete cloud recordings, chat history, or any other user-visible state on the Zoom side.
| Scope (Zoom name) | Why Cody requests it |
|---|---|
user:read:zak |
Required to fetch a ZAK token so Cody can join meetings on the authorizing user's behalf. Without this scope, the bot cannot present itself as a notetaker tied to the user; without a ZAK, it cannot join. |
user:read |
Required to identify which Zoom account authorized Cody so that we can correctly attribute artifacts (e.g., a transcript belongs to the user whose account authorized the bot) and so that we can respond to data-subject requests using verified account identifiers. We collect the user ID and the account-associated email only; no additional profile PII is read. |
meeting:read:meeting |
Required to read meeting metadata (topic, scheduled start time, host) for the meetings Cody is asked to join. Only meetings the user explicitly points Cody at — either by passing a join URL or by scheduling through a Cody-aware orchestrator — are read. Cody does not enumerate the user's full meeting list. |
Every scope is explained in plain English in the OAuth consent flow before the user accepts. If we later add a scope, that change requires both a new Marketplace review and a notification to existing authorizing users.
5. Data flows
This section walks through the seven data paths in Cody from end to end.
5.1 Authorization
The authorization flow starts in the Zoom Marketplace. The user clicks "Authorize" on the Cody listing and is redirected to Zoom's OAuth consent screen. Zoom presents the scopes from §4 above. If the user accepts, Zoom redirects back to Cody's OAuth callback endpoint with an authorization code. The callback endpoint exchanges the code for an access token and a refresh token over TLS to Zoom. Both tokens are immediately encrypted with AES-256-GCM and written to the secret store. The user's Zoom user ID and account-email are recorded against the authorization. No further information is requested or stored at this stage.
5.2 Meeting join
When the user (or an orchestrator acting for the user) requests that Cody join a meeting, the App looks up the user's encrypted refresh token, decrypts it inside the meeting-runtime service role, exchanges it for a fresh ZAK if needed, mints the SDK JWT from the Obsidian-owned SDK Key/Secret, and hands both credentials to the SDK inside a newly spawned container. The container connects to Zoom over WSS (TLS) and either joins the meeting immediately or sits in the meeting's waiting room until the host admits Cody Assistant (Notetaker).
5.3 Audio capture and transcription
Once Cody is admitted, the Meeting SDK starts delivering raw PCM audio frames via the SDK's audio-helper callback. Each frame is held briefly in an in-memory buffer inside the container. From the buffer, audio flows to two sinks:
- A rolling WAV file on the container's encrypted scratch filesystem, used to produce a meeting recording artifact at the end of the call.
- The transcription path: either a streaming connection to Deepgram (if enabled) or the local Whisper backend running inside the container.
Transcription output — text segments with timing and (where available) speaker labels — is held in memory for the duration of the meeting and serialized to the transcript artifact at meeting end. The transcript is not sent to Anthropic except when needed to answer an @cody mention or to generate the post-meeting summary; see §5.5.
5.4 Chat handling
Chat messages posted in the Zoom meeting are delivered to Cody via the SDK's chat callback. Messages addressed to Cody (those that begin with @cody or are explicitly directed to the bot's participant ID) are routed through the LLM path described below. Other messages are buffered in memory only as conversational context for the LLM and are not persisted beyond the meeting unless the user has explicitly opted in to chat retention.
5.5 Summary and reply generation
Cody calls Anthropic's Claude API for two purposes: to produce a reply when a participant addresses the bot in chat, and to generate a post-meeting summary and action-item list. In both cases, only the minimum context required is sent — typically a recent transcript window plus the chat exchange for replies, and the full transcript plus the chat log for summaries. Anthropic's commercial API terms prohibit training on customer inputs. We do not append meeting content to long-lived prompt files, vector databases, or model fine-tuning corpora.
5.6 Artifact storage
When the meeting ends or Cody is removed, the container finalizes three artifacts: the WAV recording, the transcript, and the summary/action-item document. Each is written to per-tenant encrypted storage. Each is tagged with the authorizing user's Zoom user ID, the Zoom meeting ID, and a creation timestamp. The container then terminates, and all in-memory state is destroyed.
5.7 Deletion and revocation
Users may revoke Cody's authorization from the Zoom Marketplace at any time. On revocation, Zoom invalidates the refresh token, and our token store deletes the encrypted token record within 30 days of receiving the revocation event. Users may also request artifact-level deletion at any time before the retention deadline by emailing cody@obsidian-inc.com from the email tied to their Zoom account. The default retention timer is 30 days for content artifacts (WAV, transcript, summary, chat log) and 7 days for one-off authorizations.
6. Encryption
6.1 In transit
All network traffic to and from Cody uses TLS 1.2 or higher.
- Traffic to Zoom (HTTPS for REST, WSS for signaling) is TLS-terminated by Zoom.
- Traffic to Anthropic's Claude API uses HTTPS, TLS terminated by Anthropic.
- Traffic to Deepgram (when streaming STT is enabled) uses HTTPS/WSS, TLS terminated by Deepgram.
- The public policy site on GitHub Pages is served exclusively over HTTPS.
We do not run user traffic through opportunistic-encryption channels or fall back to TLS 1.0/1.1 under any condition.
6.2 At rest
Sensitive data at rest is encrypted at the application layer and on the underlying storage volume.
- OAuth access tokens and refresh tokens are encrypted with AES-256-GCM before they touch persistent storage. The data encryption keys are managed by an environment-scoped secret store; the encryption keys are never checked into source control and are not present in the meeting-runtime container's environment except via the runtime service-role binding.
- WAV recordings, transcripts, and summaries are written to encrypted filesystems with per-tenant directory isolation. A meeting container can read and write only the directory belonging to the user whose meeting it is processing.
7. Storage and retention
The retention rules below mirror Privacy Policy §6 and are reproduced here for completeness.
- OAuth tokens are retained for the lifetime of the authorization. When the user revokes the authorization in Zoom, the refresh token is deleted within 30 days.
- Meeting WAV recordings, transcripts, chat history, and summaries are retained for 30 days by default and then permanently deleted. Users may request deletion at any time before that.
- One-off authorizations (per-meeting consent rather than persistent OAuth) result in all derived artifacts being deleted within 7 days of the meeting ending unless the user explicitly retains them.
- Diagnostic logs are retained for 90 days. They are content-redacted: they do not contain audio, transcript text, chat content, or user-readable LLM prompts; they contain only event metadata sufficient to debug failures and audit access.
- Account-level identifiers (user ID, account email) are retained while the authorization is active and deleted within 30 days of revocation.
The more restrictive of the user's explicit instruction and the default retention window governs.
8. Access controls and tenant isolation
Each meeting container runs under its own service identity and can access only that meeting's data. There is no multi-tenant data co-mingling at the storage layer or at the runtime layer.
Production deployments enforce least-privilege IAM on the secret store: only the meeting-runtime service role may decrypt OAuth tokens, and that role is bound to a single container's lifetime. Human operators do not hold blanket decryption rights against the token store; access to production data requires a documented operational reason, and all such access is logged and auditable.
The Cody operations team's day-to-day work is performed against open-source code and against ephemeral test accounts. Production user data is touched only when an incident, a data-subject request, or a debugging need requires it.
9. Subprocessor list and justifications
The same subprocessors are listed in Privacy Policy §5; this section adds the technical rationale for each.
- Zoom Video Communications, Inc. Cody cannot exist without Zoom: the Meeting SDK is the participant runtime, Zoom mints the OAuth and ZAK tokens, and Zoom signaling carries audio and chat. The data shared with Zoom is the OAuth grant, the ZAK token, and the SDK JWT; in return, Zoom delivers the audio, chat, and meeting events that Cody operates on.
- Anthropic, PBC. Cody calls Claude for in-meeting
@codyreplies and for post-meeting summary generation. The data shared with Anthropic is the transcript window and chat context required for the specific generation. Anthropic's commercial API terms prohibit training on customer inputs. - Deepgram, Inc. (optional). When streaming STT is enabled, raw PCM audio is sent to Deepgram for transcription. If Deepgram is disabled, transcription falls back to a local Whisper backend inside the meeting container, and audio leaves the container only via Zoom signaling.
- GitHub Pages. Cody's public policy and security documents are statically hosted on GitHub Pages. No user data is sent to GitHub Pages — only the HTML of these documents themselves.
No additional subprocessors handle user data. We do not use third-party analytics, advertising trackers, or behavioral-targeting services anywhere in Cody.
10. Secure development lifecycle
Cody is open-source. The full source code is published at https://github.com/CodeWarrior4Life/lattice-meetbot under the Apache 2.0 license. Anyone — Zoom reviewers, customers, security researchers — can read the implementation directly rather than rely on this document alone.
Our secure development practices include:
- Code review on every change. All changes to the public repository go through pull-request review before merging.
- Secrets via environment variables. No credential, OAuth client ID, client secret, SDK key, ZAK, JWT, or session secret is committed to source control. A pre-commit hook blocks accidental secret commits.
- Pinned dependencies. Python dependencies are pinned in
pyproject.tomlwith a correspondinguv.locklockfile. Any Node-side tooling, where used, is pinned viapackage-lock.json. Dependency updates flow through review like any other change. - Reproducible Docker builds. The container image is built on every release from a single Dockerfile checked into the repo. The Linux Meeting SDK shared library is extracted from the official Zoom tarball — not from a third-party mirror.
- Open advisories. Security-relevant issues are published as GitHub Security Advisories on the public repository.
11. Vulnerability management and disclosure
The canonical channel for vulnerability reports is GitHub Security Advisories on https://github.com/CodeWarrior4Life/lattice-meetbot. Reports can also be sent to cody@obsidian-inc.com.
Triage commitments:
- Critical and High severity: triaged within five (5) business days of receipt.
- Medium and Low severity: triaged within fifteen (15) business days.
- Coordinated disclosure: we work with reporters on a coordinated disclosure timeline that gives users adequate time to upgrade before a public advisory is published.
We do not currently offer a paid bug bounty, but we credit reporters in advisories and release notes unless the reporter requests anonymity.
12. Incident response and breach notification
If Obsidian Inc. confirms a security incident that affects user data processed through Cody, notification will follow the timelines committed to in the Privacy Policy:
- EEA / UK users: notification within seventy-two (72) hours of confirming the breach, in accordance with GDPR Article 33.
- US users: notification within thirty (30) days where applicable state law requires it, and sooner where state law requires sooner.
- Marketplace and Zoom Trust & Safety: notified in parallel for any incident affecting a Marketplace-listed integration's user data.
Each incident triggers a written post-incident review that captures root cause, customer impact, and follow-up controls. Post-incident reviews are shared with affected customers on request.
13. Compliance posture
Cody's compliance posture is intentionally conservative. We make the following statements honestly, including the ones that are negative.
- GDPR. The legal bases for processing personal data of EEA and UK users are listed in Privacy Policy §4. Data subject rights — access, correction, deletion, restriction, portability, withdrawal of consent — are honored via cody@obsidian-inc.com.
- CCPA and CPRA. We do not "sell" personal information as that term is defined under California law, and we do not "share" personal information for cross-context behavioral advertising.
- SOC 2 / ISO 27001. Cody is not currently SOC 2 or ISO 27001 certified. Both certifications are on our roadmap and will be pursued once the user base justifies the audit cost. We will update this document when certification status changes.
- HIPAA. Cody is not authorized for use in HIPAA-regulated healthcare meetings. We do not currently sign Business Associate Agreements. Do not use Cody to process Protected Health Information. If your meeting workflow requires HIPAA coverage, contact cody@obsidian-inc.com before authorizing Cody so we can confirm whether a BAA path is available for your use case.
- FedRAMP and government clouds. Cody is not authorized for FedRAMP-controlled environments or US government cloud regions.
Where a compliance regime is not listed here, customers should assume it is not in scope. We would rather be honest about our current state than overclaim and be downgraded by a reviewer for inaccuracy.
14. Open-source supply chain transparency
Cody's supply chain is intentionally legible.
- The source repository (https://github.com/CodeWarrior4Life/lattice-meetbot) is public under Apache 2.0.
- The container image is built from a single Dockerfile in that repository and published to GitHub Container Registry.
- Python dependencies are fetched from PyPI; Node-side dependencies, where used, from npm; the Linux Meeting SDK shared library is extracted from the official Zoom-published tarball.
- A Software Bill of Materials (SBOM) is available on request. We will publish SBOMs as build artifacts once tooling for our chosen format is finalized.
Reviewers and customers who want to verify that the published image matches the published source can do so by rebuilding the image from the tagged commit.
15. Operational hardening
In addition to the controls already described, the operational posture of Cody is shaped by the principle of ephemerality.
- Containers are single-purpose and short-lived. A container exists for one meeting and is destroyed at the end of that meeting. There is no long-running daemon a successful exploit could pivot through to reach other meetings.
- Configuration is environment-scoped. Each environment (development, staging, production) has its own secret store, its own Marketplace app registration, and its own OAuth client. Credentials do not cross environment boundaries.
- No interactive shells in production containers. Operations is performed by re-deploying images, not by SSH-ing into running containers. Where emergency debugging is required, audit logs capture every action.
- Logs are content-redacted. Diagnostic logs sufficient to debug failures and audit access are retained for 90 days; the contents of meetings (audio, transcripts, chat messages, LLM prompts) are not written to logs.
- Capability flags default to the most restrictive setting. Optional subprocessors (Deepgram), optional retention windows (extended transcript retention), and optional chat retention are off by default and require explicit user opt-in.
The combination of one-container-per-meeting ephemerality, environment-scoped secrets, content-redacted logs, and opt-in optional features means that the default deployment of Cody is the most privacy-preserving deployment of Cody.
16. Reviewer contact and security questions
Zoom Marketplace reviewers, security-conscious customers, and security researchers are encouraged to reach out directly.
- Security and operations: cody@obsidian-inc.com
- Engineering owner: Cyril Carrière, theblacktruth@gmail.com
- Vulnerability reports: GitHub Security Advisories at https://github.com/CodeWarrior4Life/lattice-meetbot/security/advisories
- Privacy and data-subject requests: cody@obsidian-inc.com (per Privacy Policy §8 and §13)
We will respond to security inquiries from Zoom Marketplace reviewers as a priority during the review process and within five business days otherwise.
This Security & Technical Design document is a working draft prepared for Cody Zoom Meetbot's submission to the Zoom Marketplace. It is subject to revision as the product evolves.