vercel / vercel/ai-elements

security: speech-input example exposes provider API key in client code

Open
#422 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
2.4k
Forks
283
Avg merge
32m
Merged PRs (30d)
1

Description

Summary

The current speech-input client example demonstrates sending audio directly from a "use client" component to the OpenAI transcription endpoint with:

Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`

This encourages exposing an OpenAI API key to the browser if consumers copy the example as written.

Affected files

  • skills/ai-elements/scripts/speech-input.tsx
  • skills/ai-elements/references/speech-input.md

Expected behavior

Examples should be secure by default and avoid putting secret provider API keys in client-side code. A safer example would:

  • send the audio to an application-owned server route / proxy, or
  • use a short-lived scoped token mechanism explicitly documented as browser-safe

Actual behavior

The example is a client component and performs a direct browser-side request to https://api.openai.com/v1/audio/transcriptions using process.env.NEXT_PUBLIC_OPENAI_API_KEY for the Authorization header.

Why this is a problem

NEXT_PUBLIC_* values are exposed to the browser bundle. If a developer follows this example with a real OpenAI API key, the key can be exposed in client code and/or network traffic.

This is especially risky because this file lives in a reusable example skill, so it is likely to be copied into production applications.

Steps to reproduce

  1. Open skills/ai-elements/scripts/speech-input.tsx on main.
  2. Note that the file starts with "use client".
  3. Note the direct fetch("https://api.openai.com/v1/audio/transcriptions", ...) call.
  4. Note the Authorization header uses process.env.NEXT_PUBLIC_OPENAI_API_KEY.
  5. In a Next.js app, any real value assigned to that env var will be browser-exposed.

Suggested fix

  • Replace the example with a server-mediated pattern, for example posting the recorded audio to /api/transcribe.
  • Keep the real provider key on the server only.
  • Update the docs example in skills/ai-elements/references/speech-input.md to match.
  • Optionally add an explicit note warning against putting provider secrets in NEXT_PUBLIC_* env vars.

Environment

  • Repository: vercel/ai-elements
  • Branch checked: main
  • Observed on: 2026-04-07

References

  • skills/ai-elements/scripts/speech-input.tsx
  • skills/ai-elements/references/speech-input.md
  • .github/SECURITY.md (says to report vulnerabilities by opening a new issue)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with skills/ai-elements/scripts/speech-input.tsx and skills/ai-elements/references/speech-input.md, tracing the client-side fetch and the documented usage. Replace the direct provider request with a server-mediated pattern, keep the provider key server-side, and update the documentation to match; verify that no NEXT_PUBLIC_* provider secret is used by the example.

Written by the indexing model from the issue text.

Assessment

Tech stack
nextjs, typescript
Domain
api, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.