Skip to content

safe-bash llm: OpenAI error responses bypass configured maxResponseBytes #727

Description

@kamilio

Summary

The opt-in safe-bash OpenAI LLM provider ignores a configured maxResponseBytes below 64 KiB when handling non-2xx HTTP responses. Severity: Low, a bounded resource-budget enforcement defect. No credential leak or sandbox escape is claimed.

Current-code evidence

Reviewed revision d126d35.

  • packages/safe-bash/src/commands/llm/openai-http.ts:106 calls openAiJson(response, input.signal, 64 * 1024) on errors.
  • packages/safe-bash/src/commands/llm/openai.ts constructs the configured limits but does not pass maxResponseBytes to openAiResponse.
  • packages/safe-bash/src/commands/llm/README.md:236 documents maxResponseBytes as the maximum bytes in each response body.

Reproduction

Run from repository root. Uses current TypeScript source, a fake credential and in-memory transport; no files, external requests or real LLM calls. One-byte chunks demonstrate continued consumption beyond the limit rather than merely receiving one oversized transport chunk.

// node --import tsx --input-type=module
import { createOpenAiProvider } from './packages/safe-bash/src/commands/llm/openai.ts';
let consumed = 0, disposed = 0;
const transport = async () => ({
  status: 401, statusText: 'Unauthorized', headers: [],
  body: (async function* () {
    for (const byte of new TextEncoder().encode(JSON.stringify({
      error: { message: 'denied' }, padding: '1234567890'
    }))) { consumed++; yield Uint8Array.of(byte); }
  })(),
  async dispose() { disposed++; }
});
const provider = createOpenAiProvider({
  transport, apiKey: 'mock', models: [{ id: 'chat', endpoint: 'chat' }],
  limits: { maxResponseBytes: 1 }
});
try {
  for await (const chunk of provider.complete({
    model: 'chat', prompt: 'p', attachments: [], options: {},
    signal: new AbortController().signal
  })) {}
} catch (error) {
  console.log({ error: error.message, consumed, disposed });
}

Observed independently after the Daybreak Blue scan:

{"error":"OpenAI HTTP 401: denied","configuredMaxResponseBytes":1,"responseBytesConsumed":53,"disposed":1}

Expected: error-body parsing honors the configured cap, with only bounded overflow detection, and always disposes the response. Actual: all 53 one-byte chunks are read and parsed despite the one-byte cap. The error path has its own 64 KiB ceiling, so this is not unbounded consumption and does not exceed the default 64 MiB setting.

Scope and acceptance criteria

Affected hosts must explicitly register the LLM plugin and reference provider, configure a response cap below 64 KiB, and receive an HTTP error. LLM is not included in default agentCommands.

Pass the configured budget into error handling (retaining the smaller diagnostic ceiling), add a mocked regression covering small limits and cleanup, and preserve cancellation and useful bounded error reporting. No fix is included in this report.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions