feat: support local embedded chroma with configurable CLI path#24
feat: support local embedded chroma with configurable CLI path#24yangmingyuan380 wants to merge 1 commit intoflanker:mainfrom
Conversation
flanker
left a comment
There was a problem hiding this comment.
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
chromaCliBinfromAppConfigtype, localStorage, setup page UI, query params, API route extraction, and all function signatures - In
chromaBridge.ts, resolve the binary with justprocess.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 tochromaexecutable (default:chromafrom PATH)CHROMA_LOCAL_BASE_DIR— If set, restricts local mode to subdirectories of this path
No description provided.