Skip to content

feat: support local embedded chroma with configurable CLI path#24

Open
yangmingyuan380 wants to merge 1 commit intoflanker:mainfrom
yangmingyuan380:main
Open

feat: support local embedded chroma with configurable CLI path#24
yangmingyuan380 wants to merge 1 commit intoflanker:mainfrom
yangmingyuan380:main

Conversation

@yangmingyuan380
Copy link
Copy Markdown

No description provided.

Copy link
Copy Markdown
Owner

@flanker flanker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Concerns

1. Arbitrary Binary Execution via chromaCliBin

Problem: The chromaCliBin parameter is sent from the client browser via URL query params, flows through the API route, and ultimately gets passed to spawn() in chromaBridge.ts. This means any user with access to the UI can execute any binary on the server's filesystem with controlled arguments (['run', '--host', '127.0.0.1', '--port', ...]).

Even though spawn (not exec) is used — so shell metacharacter injection isn't possible — the ability to point at an arbitrary executable is still dangerous.

Suggested fix: Remove chromaCliBin from the client entirely. The Chroma CLI path should only be configured server-side via the CHROMA_CLI_BIN environment variable:

  • Remove chromaCliBin from AppConfig type, localStorage, setup page UI, query params, API route extraction, and all function signatures
  • In chromaBridge.ts, resolve the binary with just process.env.CHROMA_CLI_BIN || 'chroma'

The principle: clients choose what to connect to (remote URL or local directory), the server controls how (which binary to run).

2. Unrestricted Filesystem Access via connectionString in Local Mode

Problem: In local mode, connectionString is a filesystem path sent from the client. resolveLocalChromaUrl calls resolve(connectionString) and then access() on it. This allows a client to:

  • Probe arbitrary directories on the server for existence and read permission
  • Serve any ChromaDB data directory on the server, even ones the user shouldn't access

For a single-user local dev tool this may be acceptable, but if the app is deployed as a shared service this becomes a real issue.

Suggested fix: Add a server-side environment variable CHROMA_LOCAL_BASE_DIR that restricts local mode to subdirectories of a configured path:

import { resolve, relative } from 'path'

function validateLocalDirectory(directory: string): string {
  const resolved = resolve(directory)
  const allowedBase = process.env.CHROMA_LOCAL_BASE_DIR

  if (!allowedBase) {
    return resolved // no restriction in single-user local mode
  }

  const resolvedBase = resolve(allowedBase)
  const rel = relative(resolvedBase, resolved)

  if (rel.startsWith('..') || resolve(resolvedBase, rel) !== resolved) {
    throw new Error(
      `Directory "${directory}" is outside the allowed base directory "${resolvedBase}".`
    )
  }

  return resolved
}

Then document both env vars in the README:

  • CHROMA_CLI_BIN — Path to chroma executable (default: chroma from PATH)
  • CHROMA_LOCAL_BASE_DIR — If set, restricts local mode to subdirectories of this path

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants