kimi-code/packages/server/test
Kai db61c9e2dd
fix: refuse unsupported image formats instead of poisoning sessions (#1536)
* fix: refuse unsupported image formats instead of poisoning sessions

Images in formats providers reject (AVIF, HEIC, BMP, TIFF, ICO) used to
pass through to the API, and the resulting HTTP 400 repeated on every
later turn because the image_url stayed in the session history.

Add a single format policy (accepted set: PNG/JPEG/GIF/WebP) enforced at
every ingestion point: ReadMediaFile refuses with a per-OS conversion
command; MCP tool results, REST uploads, and ACP prompts replace the
image with a text notice; and turn.prompt/steer gates as the last-funnel
backstop so the SDK/RPC path cannot poison a session either. Accepted
MIME aliases (image/jpg, case/whitespace) are forwarded in canonical
form, and data URLs carrying MIME parameters can no longer slip past the
gate. Remote image URLs pass through (no bytes to inspect).

* fix: canonicalize accepted data URLs with MIME parameters

The format gate compared only the MIME token when deciding whether to
rebuild a data URL, so an accepted image carrying MIME parameters
(`data:image/jpeg;charset=utf-8;base64,...`) was forwarded with its
original header. The Anthropic provider splits the data URL and
exact-matches the full header against its whitelist, so the part still
poisoned the session. Rebuild to the byte-exact canonical URL whenever
the original differs, covering aliases, case/whitespace, and parameters
with one comparison.

Addresses review feedback on PR #1536.

* fix: parse data URLs case-insensitively in the image format gate

An uppercase `;BASE64,` marker is legal (RFC 2045 encoding names are
case-insensitive), but the parser required a lowercase match and
returned null, so the gate treated the URL as remote and forwarded it:
an unsupported image could still land in the session history, and the
Anthropic provider's lowercase-only split then threw on every turn.
Match the scheme and marker case-insensitively; the canonical rebuild
emits the lowercase form.

Addresses review feedback on PR #1536.

* fix: harden image format handling against mislabeled and legacy images

Two more ways an unsupported image could reach the provider are closed:

- Bytes, not labels, decide the format. A data-URL image whose declared
  MIME disagrees with its magic bytes (e.g. AVIF bytes an image search
  tool labels image/png) is now gated on the sniffed format at every entry
  point (MCP results, ACP, SDK/RPC prompt, REST inline and file uploads),
  so a mislabel cannot slip past the gate.
- A poisoned image already in the session history no longer kills the
  session: a server image-format 400 (or kosong's client-side image
  rejection) now retries once with every media part replaced by a text
  marker, mirroring the 413 media-degraded recovery. The recovery also
  fires during compaction, and the transient-retry fallback no longer
  burns the retry budget on image-format errors before the dedicated
  recovery can run.

* fix: reject remote image URLs ending in an unsupported extension

Remote image URLs (MCP resource_link, REST `kind: 'url'`) carry no bytes
to sniff, so a link ending in `.avif` (or `.heic`, `.bmp`, `.tiff`,
`.ico`) would pass through and be fetched server-side — and rejected.
Reject such URLs by their path extension instead (query/fragment
ignored, case-insensitive); extensionless or accepted-extension URLs
still pass through to the provider and the 400 recovery.

* fix: tighten image format handling for parameterized MIMEs and recovery scope

Address two review findings on PR #1536:

- A declared media type with parameters (e.g. image/jpeg; charset=utf-8)
  is no longer misread as unsupported: normalizeImageMime now strips
  parameters, matching the data-URL parser, so an accepted image with
  parameters is forwarded instead of dropped.
- The image-format recovery predicate is narrowed to specific
  format/data rejection phrases, so a 400 about image count, size, or
  image-input support no longer triggers a media-stripped resend that
  would let the model answer blind to the user's images.

* fix

* fix: scope image format recovery to images and flag remote SVG URLs

- The media_type/mime_type recovery match now requires the message to
  mention an image, so a video/audio media_type rejection surfaces
  instead of triggering a blind media-stripped resend.
- unsupportedImageMimeFromUrl flags .svg URLs as image/svg+xml without
  touching the shared suffix map (SVG stays text for the file tools),
  so remote SVG images get the intended notice instead of a provider
  rejection.

Addresses review feedback on PR #1536.

* fix: reject remote MCP images by their declared MIME type

An MCP resource_link with an extensionless or signed URL gives the
extension gate nothing to work with, and convertMCPContentBlock was
discarding the declared mimeType — an honestly-declared AVIF/HEIC link
from an image search tool still became an image_url and poisoned the
session. Reject on the declared MIME when the server provides one:
unsupported declarations become a text notice that keeps the URL so the
model can fetch and convert it; accepted declarations pass through as
before.

Addresses review feedback on PR #1536.

* fix: keep image format recovery image-specific and preserve dropped URLs in notices

- Drop the bare `media` alternative from the image-format recovery
  patterns so audio/video media rejections ("unsupported media type",
  "invalid media type") can never be misclassified as image errors and
  blindly media-stripped; every pattern now mentions "image" literally.
- Remote image URLs rejected by their extension now keep the URL in the
  replacement notice (gateImageFormatParts and the REST url path), so the
  model can still fetch and convert the image — matching the declared-MIME
  resource_link path.

Addresses review feedback on PR #1536.

* fix: drop malformed data URLs at ingestion instead of letting them poison the session

A `data:` URL that fails to parse (missing `;base64,` separator, empty
MIME, …) was treated like a remote URL and passed through the format
gate; the provider then rejects it on every turn, and the read-side
media-stripped recovery keeps paying that round-trip until compaction.
Detect unparseable `data:` URLs in gateImageFormatParts and replace them
with a (truncated) notice at ingestion, covering the MCP/ACP/SDK/turn
paths that share the gate.

Addresses review feedback on PR #1536.
2026-07-10 19:36:00 +08:00
..
__snapshots__ feat(skills): list workspace skills without a session (#1392) 2026-07-05 18:05:15 +08:00
helpers feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
svc ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
anti-corruption.test.ts feat(web): introduce Kimi web app and daemon gateway (#625) 2026-06-17 20:53:46 +08:00
api-surface.snapshot.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
approval.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
auth-middleware.e2e.test.ts feat(server): add --dangerous-bypass-auth and --keep-alive flags (#1368) 2026-07-04 18:03:50 +08:00
auth-wiring.e2e.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
auth.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
authTokenService.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
bindClassify.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
config.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
connections.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
debug-nonloopback.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
defineRoute.test.ts feat(web): introduce Kimi web app and daemon gateway (#625) 2026-06-17 20:53:46 +08:00
error-handler.test.ts feat(web): introduce Kimi web app and daemon gateway (#625) 2026-06-17 20:53:46 +08:00
fileLaunch.test.ts feat(web): introduce Kimi web app and daemon gateway (#625) 2026-06-17 20:53:46 +08:00
files.e2e.test.ts fix(web): make uploaded videos play in the chat (#1343) 2026-07-04 00:36:00 +08:00
fs-basic.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
fs-batch.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
fs-browse.e2e.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
fs-download.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
fs-git.e2e.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
fs-mkdir.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
fs-path-safety.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
fs-search.e2e.test.ts chore(telemetry): add ripgrep fallback telemetry (#1203) 2026-06-29 18:30:09 +08:00
fs-watch.e2e.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
guiStore.e2e.test.ts feat(server): add GUI store API mirroring localStorage (#1231) 2026-06-30 21:04:59 +08:00
host-exposure.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
host-origin.e2e.test.ts feat(server): add --allowed-host flag for DNS-rebinding allowlist (#1128) 2026-06-26 17:06:01 +08:00
hostnames.test.ts feat(server): add --allowed-host flag for DNS-rebinding allowlist (#1128) 2026-06-26 17:06:01 +08:00
lock.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
messages.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
meta.e2e.test.ts feat(server): add --dangerous-bypass-auth and --keep-alive flags (#1368) 2026-07-04 18:03:50 +08:00
model-catalog-refresh-scheduler.test.ts feat(server): auto-refresh provider model catalog and push change events (#1207) 2026-06-30 12:29:10 +08:00
model-catalog.e2e.test.ts feat(server): auto-refresh provider model catalog and push change events (#1207) 2026-06-30 12:29:10 +08:00
oauth.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
origin.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
prompt.e2e.test.ts fix: refuse unsupported image formats instead of poisoning sessions (#1536) 2026-07-10 19:36:00 +08:00
question.e2e.test.ts feat(agent-core): feed AskUserQuestion answers back as question text and option labels (#1414) 2026-07-06 16:37:54 +08:00
rate-limit.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
security-headers.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
services-auth.test.ts fix(server): skip Unix-only permission check on Windows for server token (#1135) 2026-06-26 18:38:24 +08:00
services.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
sessions-workspace.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
sessions.e2e.test.ts feat(server): support restoring and listing archived sessions (#1073) 2026-07-06 20:09:45 +08:00
skills.e2e.test.ts feat(skills): list workspace skills without a session (#1392) 2026-07-05 18:05:15 +08:00
snapshot.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
snapshot.perf.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
snapshot.smoke.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
snapshotService.unit.test.ts feat(agent-core): rework compaction to keep only user prompts and summary (#1214) 2026-07-01 01:17:30 +08:00
start.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
swagger.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
tasks.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
terminals.e2e.test.ts ci: run unit tests on windows (#1037) 2026-06-26 11:56:41 +08:00
terminalTestBackend.ts feat(web): introduce Kimi web app and daemon gateway (#625) 2026-06-17 20:53:46 +08:00
tools.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
workspaces.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
ws-abort.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
ws-auth.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
ws-broadcast.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
ws-handshake.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
ws-resync.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00
ws-terminal.e2e.test.ts feat(server): add bearer-token auth and safe host exposure (#1006) 2026-06-25 17:57:56 +08:00