You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The chat/fix agent workflow (ChatSession) is designed to inspect, edit, and commit code changes in the target repository. However, it does not check whether the repository has uncommitted changes before beginning. The system prompt instructs the agent to check git status and ask before staging, but this is a best-effort LLM instruction — not a hard enforcement. If the model misinterprets instructions or encounters an adversarial repo, it can silently overwrite or stage uncommitted work, causing irreversible data loss.
System prompt instructs agent to check git but does not enforce it
src/server/chat.ts
L230–L302
runAgent() starts immediately with no preflight
src/server/routes.ts
L470–L485
/chat/:slug/:id/messages route has no repo dirty-check before dispatching
Root Cause — Code Evidence
System prompt relies on LLM compliance, not code enforcement (src/server/chat.ts, lines 66–70):
constSYSTEM_PROMPT_TEMPLATE=`// ...4. Check git state with \`git status\`. If the repo is dirty with unrelated changes, ASK before staging.// ...`// ↑ This is a soft instruction. An agent running with bypassPermissions can still// execute 'git add -A && git commit' without asking if it misreads the instruction.
No preflight in runAgent() (src/server/chat.ts, line 230):
privateasyncrunAgent(): Promise<void>{this.setStatus('streaming');this.abortCtrl=newAbortController();// ↑ Agent starts immediately — no git status check, no stash, no user confirmation// before the agent has file-write + shell access to the repo.
Impact
Data loss: Uncommitted changes in the target repo (e.g. half-written features, sensitive local configurations) can be overwritten or staged by the agent without warning.
Irreversibility: If the agent stages and amends an existing commit, local changes may be unrecoverable without git reflog.
Start Probus and initiate a chat fix session for a vulnerability report in that repo.
Send a message like "Please apply the fix and create a PR".
Observe whether the agent checks git status before writing files. In adversarial or rushed scenarios, it may skip this step.
Remediation
Step 1 — Perform a server-side git dirty check before starting the agent
// src/server/chat.ts — add to sendMessage() or runAgent() preambleimport{execFileSync}from'node:child_process';functionisRepoDirty(repoPath: string): boolean{try{constout=execFileSync('git',['status','--porcelain'],{cwd: repoPath,encoding: 'utf8',timeout: 5000,});returnout.trim().length>0;}catch{returnfalse;// not a git repo or git not installed — allow agent to proceed}}
Step 2 — Block or warn before starting the agent on a dirty repo
asyncsendMessage(text: string): Promise<void>{if(this.status==='streaming'){thrownewError('Agent is still responding.');}// Preflight: warn if repo has uncommitted changesif(isRepoDirty(this.repoPath)){// Option A: Hard block (safest)thrownewError('Repository has uncommitted changes. Stash or commit them before running the fix agent.');// Option B: Soft warning — emit a warning event but continue// this.emit({ type: 'error', message: 'Warning: repo has uncommitted changes.' });}// ... rest of sendMessage unchanged}
Step 3 — Auto-stash before agent runs (advanced option)
// Stash uncommitted changes, run agent, then offer to pop stash on completionexecFileSync('git',['stash','push','-m','probus-auto-stash'],{cwd: this.repoPath});// ... run agent ...// After agent finishes:// execFileSync('git', ['stash', 'pop'], { cwd: this.repoPath });
Summary
The chat/fix agent workflow (
ChatSession) is designed to inspect, edit, and commit code changes in the target repository. However, it does not check whether the repository has uncommitted changes before beginning. The system prompt instructs the agent to checkgit statusand ask before staging, but this is a best-effort LLM instruction — not a hard enforcement. If the model misinterprets instructions or encounters an adversarial repo, it can silently overwrite or stage uncommitted work, causing irreversible data loss.Panel verdict: P1, VERIFIED, EXISTING_DEFECT, consensus.
Affected Files
src/server/chat.tssrc/server/chat.tsrunAgent()starts immediately with no preflightsrc/server/routes.ts/chat/:slug/:id/messagesroute has no repo dirty-check before dispatchingRoot Cause — Code Evidence
System prompt relies on LLM compliance, not code enforcement (
src/server/chat.ts, lines 66–70):No preflight in
runAgent()(src/server/chat.ts, line 230):Impact
git reflog.bypassPermissions(Issue [P0][SECURITY] Unauthenticated loopback RCE via bypassPermissions + missing CORS/CSRF guards #1), the agent has no filesystem restrictions — it can modify any file, not just those in the target repo.Steps to Reproduce
git statusbefore writing files. In adversarial or rushed scenarios, it may skip this step.Remediation
Step 1 — Perform a server-side git dirty check before starting the agent
Step 2 — Block or warn before starting the agent on a dirty repo
Step 3 — Auto-stash before agent runs (advanced option)
References