v2.9.3 — a decode ceiling that covers the write side, and a fence around compressed shell output
Bounds every image decode and every shrink write against a fixed 256 MB ceiling, adds a static pass over every interpreter sink in the source tree plus a CodeQL dataflow job, fences compressed shell output and background poll deltas as untrusted content, and defuses text that impersonates token-goat’s own marker from inside the fence.
Security
- Image decoders refuse files that would allocate gigabytes, hang, or return the wrong picture: a 64-byte TIFF that never returned, an 11.5 KB GIF asking for 5.1 GB, a PNG expanding 61 MB of data to 512 MB. The ceiling covers the shrink write path too, which cost five bytes per pixel per frame where the read cost four. The PNG and BMP decoders now stop rather than hand the model a re-encoded wrong picture.
- The suite runs a static pass over every interpreter sink in
src, and CI runs the dataflow half as a CodeQL job.eslint-plugin-securitywas measured (1,691 findings across 177 of 255 files) and rejected, with the measurement written down. - The Copilot CLI hook shim rejects an event name it never declared: eight
Object.prototypenames answered its lookup truthily and reached a shell. - Compressed shell output, background shell polls, and background task polls now reach the model inside an untrusted-content fence, and text impersonating token-goat’s
[token-goat: ...]prefix is defused. Measured: an impersonation attempt drew compliance 11 of 12 times unfenced, 6 of 12 fenced, 1 of 12 with the prefix escaped.
Fixed
- A shrunk PNG or GIF served from the image cache is no longer announced to the model as a WebP.
token-goat image-metano longer carries a fallback pointing at a library that cannot help.- The README described an image pipeline token-goat no longer has.
- Verbose vitest output is compressed: a 22,684-byte run came back 2 bytes smaller, now 348 bytes.
Added
token-goat benchscores the shell-output compressors through the same function that decides what a real command hands back to the model.
Full detail: CHANGELOG.md.