Skip to content

Commit a3acea8

Browse files
committed
fix(inworld): enforce decoded TTS audio cap
1 parent e76638d commit a3acea8

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

extensions/inworld/tts.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,18 @@ describe("Inworld response read bounding", () => {
406406
expect(audio.toString("utf8")).toBe(payload);
407407
});
408408

409+
it("fail-closed: rejects decoded audio that exceeds the shared audio cap", async () => {
410+
const decodedPayload = Buffer.alloc(16 * MiB + 1, 0x61);
411+
const body = JSON.stringify({
412+
result: { audioContent: decodedPayload.toString("base64") },
413+
});
414+
queueGuardedResponse(new Response(body, { status: 200 }));
415+
416+
await expect(inworldTTS({ text: "test", apiKey: "test-key" })).rejects.toThrow(
417+
/Inworld TTS decoded audio too large: 16777217 bytes \(limit: 16777216 bytes\)/,
418+
);
419+
});
420+
409421
it("regression: a malformed NDJSON line under the cap still throws a bounded parse error", async () => {
410422
queueGuardedResponse(new Response("this-is-not-json", { status: 200 }));
411423
await expect(inworldTTS({ text: "test", apiKey: "test-key" })).rejects.toThrow(

extensions/inworld/tts.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export async function inworldTTS(params: {
160160
})
161161
).toString("utf8");
162162
const chunks: Buffer[] = [];
163+
let decodedAudioBytes = 0;
163164

164165
for (const line of body.split("\n")) {
165166
const trimmed = line.trim();
@@ -184,7 +185,15 @@ export async function inworldTTS(params: {
184185
}
185186

186187
if (parsed.result?.audioContent) {
187-
chunks.push(Buffer.from(parsed.result.audioContent, "base64"));
188+
const chunk = Buffer.from(parsed.result.audioContent, "base64");
189+
const nextDecodedAudioBytes = decodedAudioBytes + chunk.length;
190+
if (nextDecodedAudioBytes > MAX_AUDIO_BYTES) {
191+
throw new Error(
192+
`Inworld TTS decoded audio too large: ${nextDecodedAudioBytes} bytes (limit: ${MAX_AUDIO_BYTES} bytes)`,
193+
);
194+
}
195+
decodedAudioBytes = nextDecodedAudioBytes;
196+
chunks.push(chunk);
188197
}
189198
}
190199

0 commit comments

Comments
 (0)