fix: resolve security-audit findings across both SDKs#163
Merged
Conversation
Bug fixes (confirmed on main by a full-codebase audit): - Python: TwilioAudioSender.send_mark / Plivo checkpoint discarded the caller-supplied mark name and sent a locally generated audio_N instead, so the first-message pacer's fm_N echo never matched and every mark resolved via the 0.5s fallback timeout (~1.5s guaranteed extra latency in the barge-in window of every Twilio call). - TypeScript: handler.handleAudio(...) was un-awaited in all three carrier WS message handlers — a rejection in the audio path escaped the try/catch and killed the Node process as an unhandled rejection. - TypeScript: the Telnyx WS close handler never deleted its activeCallIds entry (Twilio/Plivo did), leaking map entries for the server lifetime and firing hangups for dead calls on graceful shutdown. - Both: pipeline context rebuild replayed role="tool" history entries as fabricated user turns containing raw tool JSON; they are now skipped. - Python: deprecated asyncio.get_event_loop() removed from running-loop contexts (stream_handler mark waiter, ElevenLabs WS TTS cancel path — the latter now schedules close on the loop captured at stream start with a done-callback surfacing errors). - Python: pre-barge-in inbound audio ring converted to deque(maxlen=13) (O(1) eviction in the per-frame hot path) with a snapshot before the async replay to avoid mutation-during-iteration. Security hardening: - Telnyx anti-replay window aligned across SDKs: future-dated timestamps rejected beyond a 30s clock-skew allowance (Python previously accepted up to +300s via abs(); TypeScript rejected ANY future timestamp, dropping legitimate webhooks on clock-lagged hosts). - TypeScript sanitizeVariables now strips control characters and caps values at 500 chars (parity with Python _sanitize_variable_value) — caller-supplied template variables reach the system prompt. - TypeScript LLM API error bodies truncated to 200 chars in logs (401 bodies can embed the rejected API-key prefix). Regression tests added/updated in both SDKs for every fix.
Resolves 4 moderate hono advisories (IPv6 deny-rule bypass, Set-Cookie injection, JWT scheme laxness, percent-encoded mount routing) and the dev-only critical vitest UI arbitrary-file-read advisory. Lockfile-only change; both versions move within existing semver ranges. npm audit is clean after the bump.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
hono×4 moderate,vitestdev-only critical) via a lockfile-only bump;npm auditandpip-auditare both clean.Implementation
Bug fixes
telephony/twilio.py/telephony/plivo.py(Python):send_marknow puts the caller-supplied name on the wire instead of a locally generatedaudio_N, so the first-message pacer'sfm_Necho matches and marks resolve via carrier echo instead of burning the 0.5s timeout (×3 marks per call). Matches the TypeScript behaviour.src/server.ts: the three carrier WS message handlers nowawait handler.handleAudio(...)— a rejection in the audio hot path (~50 frames/s) previously escaped thetry/catchand terminated the process as an unhandled rejection.src/server.ts: the Telnyx WS close handler now deletes itsactiveCallIdsentry (Twilio/Plivo already did), fixing an unbounded map leak plus spurious hangup REST calls at graceful shutdown.services/llm_loop.py/src/llm-loop.ts: pipeline context rebuild skipsrole="tool"history entries instead of replaying them as fabricated user turns containing raw tool JSON.stream_handler.py,providers/elevenlabs_ws_tts.py(Python): deprecatedasyncio.get_event_loop()removed from running-loop contexts; the ElevenLabs barge-in cancel schedules the close on the loop captured at stream start, with a done-callback surfacing close errors.stream_handler.py(Python): pre-barge-in inbound audio ring is nowdeque(maxlen=13)(O(1) eviction in the per-frame path) with a snapshot before the async replay.Security
[-30s, +300s]in both. Python previously accepted up to +300s in the future (abs()check — doubled replay window); TypeScript rejected ANY future timestamp (dropped legitimate webhooks on clock-lagged hosts).sanitizeVariables(TS) now strips control chars and caps values at 500 chars, byte-for-byte parity with Python_sanitize_variable_value(caller-supplied carrier custom params reach the system prompt).Deps: lockfile-only
npm audit fix(hono ≥4.12.21, vitest ≥3.2.6), separate commit.No new dependencies. No public API changes.
Breaking change?
No. The only behaviour changes are: (a) Telnyx webhooks dated >30s in the future are now rejected by Python (previously ≤300s accepted) — within spec for signed-webhook freshness; (b) TS now ACCEPTS ≤30s future skew (previously rejected) — strictly fewer false rejections; (c) TS template variables are sanitised like Python already was.
Test plan
pytest tests/ -m "not soak"— 2360 passed, 7 skipped, 2 xfailednpm test(1823 passed across 114 files) +npm run lint+npm run build— clean, re-run after the dependency bumpnpm audit→ 0 vulnerabilities;pip-audit→ cleanDocs updates
## Unreleased→### Fixed/### Security)