fix: validate and re-cap all inbound worker-port traffic (Codex round 1)
The host's message listener trusted the compile-time WorkerToHost shape on traffic from a peer that runs model code: postMessage(null) threw in the listener and crashed the host process; forged log/done messages bypassed maxLogBytes/maxValueBytes (the worker-side LogBuffer and prepareValue cap only honest flows); and the error-reply renegotiation re-echoed a forged non-cloneable call id, throwing outside any catch. Every inbound message now passes a runtime shape gate that validates and REBUILDS it field by field (junk drops without a throw; call ids must be numbers, so replies are always clone-plain; forged extra fields never ride along). One host-side ledger bounds everything landing in logs — honest port entries, forged ones, and stray pipe bytes — at the single documented maxLogBytes, with the shared in-band truncation marker emitted host-side when the ledger trips first; the completion value is re-capped host-side through the same prepareValue (with exactly the truncation suffix as slack so honest worker-capped values pass unchanged), and done error text is bounded. Also folds the stray-capture budget into that shared ledger (round-1 finding B: it was a second maxLogBytes on top of the documented shared cap).
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
|
||||
import { inspect } from 'node:util'
|
||||
import type { CodeLogEntry } from '@deepseek-ai/dsh-code-runtime'
|
||||
import { logTruncationMarker } from './protocol.ts'
|
||||
import type { DoneMessage, ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts'
|
||||
|
||||
/** The port surface the bootstrap needs — satisfied by `parentPort` and by the tests' fake. */
|
||||
@@ -62,7 +63,7 @@ export class LogBuffer {
|
||||
const cost = Buffer.byteLength(entry.text, 'utf8')
|
||||
if (cost > this.remaining) {
|
||||
this.truncated = true
|
||||
this.sink({ source: 'stderr', text: `[dsh-code-runtime-worker] log capture truncated at ${this.maxBytes} bytes` })
|
||||
this.sink({ source: 'stderr', text: logTruncationMarker(this.maxBytes) })
|
||||
return
|
||||
}
|
||||
this.remaining -= cost
|
||||
|
||||
Reference in New Issue
Block a user