Skip to content

fix(inworld): reject malformed base64 TTS audio#111197

Merged
sallyom merged 1 commit into
openclaw:mainfrom
ZengWen-DT:fix/inworld-malformed-base64-tts
Jul 20, 2026
Merged

fix(inworld): reject malformed base64 TTS audio#111197
sallyom merged 1 commit into
openclaw:mainfrom
ZengWen-DT:fix/inworld-malformed-base64-tts

Conversation

@ZengWen-DT

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where users generating speech with Inworld TTS could receive silently corrupted audio when the provider returned malformed base64 in an otherwise successful response.

Why This Change Was Made

The Inworld response path now validates and canonicalizes each audio chunk with the shared media-runtime base64 contract before concatenation, while preserving valid padded, unpadded, URL-safe, and whitespace-bearing base64. Risk note: rejecting a valid provider payload would break TTS, so the existing success cases and a real production-entry transport harness cover both valid decoding and malformed rejection.

User Impact

Malformed Inworld audio now fails with a clear provider error instead of being decoded into plausible but corrupted bytes.

Evidence

Node v24.18.0 on Linux x64 demonstrates the underlying runtime behavior: Buffer.from("aGVs!bG8=", "base64") silently returns hello even though the payload contains an invalid character. Inworld's voice preview contract exposes audioContent as base64: https://dev.docs.inworld.ai/api-reference/voiceAPI/voiceservice/get-voice-preview

Before, the real inworldTTS production entry at upstream/main@c684b132133 accepted that malformed provider value through a transport-only fetch stub:

{ surface: "inworld", malformed: "aGVs!bG8=", acceptedUtf8: "hello" }

After this change, the same production entry and transport-only harness rejects it:

{ rejected: true, error: "Inworld TTS returned malformed base64 audio data" }

Focused repository test:

$ OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/inworld/tts.test.ts
Test Files  1 passed (1)
Tests       31 passed (31)

Touched-file oxfmt, oxlint, and git diff --check passed. The final autoreview completed cleanly with 0.95 confidence.

AI-assisted: Codex helped implement and review the change; production-entry proof and focused validation were run manually.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jul 19, 2026
@clawsweeper

clawsweeper Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 19, 2026, 12:19 AM ET / 04:19 UTC.

Summary
The PR canonicalizes and validates Inworld TTS base64 audio chunks before decoding, then adds a regression test for malformed provider audio.

PR surface: Source +4, Tests +9. Total +13 across 2 files.

Reproducibility: yes. in source, with medium confidence: the supplied production-entry transport harness demonstrates that Node’s permissive base64 decoder accepts an invalid character, and the added focused test exercises the same Inworld response path. A fresh current-main rerun was not established in the supplied evidence.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: extensions/inworld/tts.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Next step before merge

  • [P2] No narrow repair is needed; normal PR merge refresh and exact-head check gating are the remaining actions.

Security
Cleared: The two-file diff adds no dependency, workflow, permission, secret, artifact-execution, or supply-chain surface; it rejects malformed untrusted provider data before decoding.

Review details

Best possible solution:

Keep the provider-owned strict validation through the shared base64 contract, retain coverage for malformed and supported valid payload forms, and merge once the normal exact-head checks and merge refresh permit it.

Do we have a high-confidence way to reproduce the issue?

Yes in source, with medium confidence: the supplied production-entry transport harness demonstrates that Node’s permissive base64 decoder accepts an invalid character, and the added focused test exercises the same Inworld response path. A fresh current-main rerun was not established in the supplied evidence.

Is this the best way to solve the issue?

Yes. Validating at the Inworld provider boundary with the existing shared media-runtime canonicalizer is narrower and more maintainable than adding a local parser or allowing malformed provider bytes to reach concatenation.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 16e967eb7f53.

Label changes

Label changes:

  • add P2: This fixes silent corruption in one optional provider’s TTS response path, with a limited but user-visible blast radius.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides after-fix terminal/live output from the real inworldTTS production entry using a transport-only response stub, showing malformed data is rejected, plus focused test output; redact any private provider details if further evidence is posted.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body provides after-fix terminal/live output from the real inworldTTS production entry using a transport-only response stub, showing malformed data is rejected, plus focused test output; redact any private provider details if further evidence is posted.

Label justifications:

  • P2: This fixes silent corruption in one optional provider’s TTS response path, with a limited but user-visible blast radius.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body provides after-fix terminal/live output from the real inworldTTS production entry using a transport-only response stub, showing malformed data is rejected, plus focused test output; redact any private provider details if further evidence is posted.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides after-fix terminal/live output from the real inworldTTS production entry using a transport-only response stub, showing malformed data is rejected, plus focused test output; redact any private provider details if further evidence is posted.
Evidence reviewed

PR surface:

Source +4, Tests +9. Total +13 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 6 2 +4
Tests 1 9 0 +9
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 15 2 +13

What I checked:

  • Shared validation boundary: The patch replaces permissive Buffer.from(..., "base64") decoding with canonicalizeBase64 from openclaw/plugin-sdk/media-runtime, preserving the repository’s shared media parsing contract before decoding provider data. (extensions/inworld/tts.ts:189, 56133b13b887)
  • Focused regression coverage: The added test supplies malformed audioContent through the Inworld response path and asserts the provider-specific rejection error. (extensions/inworld/tts.test.ts:240, 56133b13b887)
  • After-fix behavior proof: The PR body records a transport-only harness reaching the real inworldTTS entry: malformed aGVs!bG8= was previously decoded as hello and is rejected after the change; it also reports the focused test suite passing 31 tests. (extensions/inworld/tts.ts:189, 56133b13b887)
  • Repository policy: The supplied full root policy requires provider-owned behavior to remain in the owner plugin and directs dependency-backed validation to shared contracts; this patch stays inside the Inworld extension and imports the documented plugin SDK media runtime. (AGENTS.md:1, 16e967eb7f53)

Likely related people:

  • unknown: The supplied context identifies the proposed branch author but contains no current-main blame or feature-history metadata for the Inworld TTS implementation; the contributor is therefore not treated as the code owner. (role: current-main history owner unresolved; confidence: low; files: extensions/inworld/tts.ts, extensions/inworld/tts.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@sallyom

sallyom commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Merge-ready with one PR-body correction to remove claim that URL-safe Base64 is preserved. The shared canonicalizeBase64 validator intentionally accepts only the standard +// alphabet, while Inworld documents standard Base64. No runtime change is needed for the documented provider contract. HEAD: 56133b13b8870a72e454d6029470588c7d4dedd8

@sallyom
sallyom merged commit 27f05c8 into openclaw:main Jul 20, 2026
128 of 134 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: inworld Extension: inworld P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants