Security & robustness hardening pass

Cross-cutting input-validation, isolation, and DoS-resistance fixes across
the app, API, billing, queue, and infra layers.

- Runtime validation (zod) for client-supplied admin actions (role/plan/
  limits), series generation index, and all pg-boss queue payloads
- Auth: require email verification before sign-in; reject weak/placeholder/
  short BETTER_AUTH_SECRET in production
- Billing: sanitize Stripe/PayPal errors (log server-side, generic to client);
  race-safe subscription upsert; only count "processed" webhook events as
  handled; verify org membership in getEffectivePlan to block plan escalation
- Series generation: reserve usage up front and refund on failure; bill the
  owning org, not the caller's active org
- Injection defenses: HTML-escape user fields in emails, strip CR/LF from
  subject/recipient, validate ElevenLabs voiceId before URL interpolation
- Media routes: stream off disk instead of buffering whole files; rate-limit
  anonymous public audio/cover endpoints by client IP
This commit is contained in:
Leon Serfaty
2026-06-20 20:59:03 -04:00
parent cd1d6a1a28
commit 51c541ad22
21 changed files with 489 additions and 152 deletions
+12 -1
View File
@@ -5,12 +5,23 @@ const TTS_MODEL = process.env.ELEVENLABS_TTS_MODEL ?? "eleven_multilingual_v2";
const DIALOGUE_MODEL = process.env.ELEVENLABS_DIALOGUE_MODEL ?? "eleven_v3";
const OUTPUT_FORMAT = "mp3_44100_128";
/** ElevenLabs voice IDs are opaque alphanumeric tokens; reject anything else. */
const VOICE_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
function apiKey(): string {
const k = process.env.ELEVENLABS_API_KEY;
if (!k) throw new Error("ELEVENLABS_API_KEY is not set");
return k;
}
/** Validate a voice ID before it is interpolated into a request URL path. */
function safeVoiceId(voiceId: string): string {
if (!VOICE_ID_PATTERN.test(voiceId)) {
throw new Error(`Invalid ElevenLabs voiceId: ${voiceId}`);
}
return encodeURIComponent(voiceId);
}
interface ElevenVoice {
voice_id: string;
name: string;
@@ -28,7 +39,7 @@ export class ElevenLabsAudioProvider implements AudioProvider {
_opts?: { language?: string }
): Promise<{ audio: Buffer; characters: number }> {
const res = await fetch(
`${API}/text-to-speech/${voiceId}?output_format=${OUTPUT_FORMAT}`,
`${API}/text-to-speech/${safeVoiceId(voiceId)}?output_format=${OUTPUT_FORMAT}`,
{
method: "POST",
headers: {