ruvnet/ruflo · error · Error
Invalid git ref: contains unsafe characters
Error message
Invalid git ref: contains unsafe characters
What it means
Thrown by validateGitRef(ref) when ref contains any character outside the safe set [a-zA-Z0-9_\-./~^@]. This is the first of three guards in getGitDiffNumstat's input validation, designed to block shell metacharacters before ref is passed to git via execFileSync. Even though execFileSync uses an args array (no shell), the denylist is defense-in-depth against argument-injection vectors. Refuses hard.
Source
Thrown at v3/@claude-flow/cli/src/ruvector/diff-classifier.ts:373
recommendedReviewers?: string[];
}
// ============================================================================
// Optimized Git Diff Functions
// ============================================================================
// Cache for diff results (TTL-based)
const diffCache = new Map<string, { files: DiffFile[]; timestamp: number }>();
const CACHE_TTL_MS = 5000; // 5 seconds - short TTL since diffs change frequently
/**
* Validate git ref to prevent command injection
* Only allows safe characters: alphanumeric, -, _, /, ., ~, ^
*/
function validateGitRef(ref: string): void {
// Block shell metacharacters and dangerous patterns
if (!/^[a-zA-Z0-9_\-./~^@]+$/.test(ref)) {
throw new Error(`Invalid git ref: contains unsafe characters`);
}
// Block multiple dots (path traversal)
if (ref.includes('..') && !ref.match(/^[a-zA-Z0-9_\-]+\.\.\.?[a-zA-Z0-9_\-]+$/)) {
if (!/^\w+\.\.[.\w]+$/.test(ref)) {
throw new Error(`Invalid git ref: suspicious pattern`);
}
}
// Max length check
if (ref.length > 256) {
throw new Error(`Invalid git ref: too long`);
}
}
/**
* Get git diff statistics using SINGLE combined command (optimized)
* Replaces two separate git commands with one
*/
export function getGitDiffNumstat(ref: string = 'HEAD'): DiffFile[] {View on GitHub (pinned to 6b01dc5a68)
Solutions
- Strip/trim the ref before validation and reject anything containing whitespace.
- If you allow user input, validate against an explicit allowlist of known refs (git branch --list output) rather than passing raw.
- Normalize backslashes to forward slashes on Windows BEFORE validation.
- Never build the ref by concatenating untrusted segments — use a fixed schema.
Example fix
// before
const files = getGitDiffNumstat(req.query.ref);
// after — sanitize then validate
const ref = String(req.query.ref ?? 'HEAD').trim().replace(/\\/g, '/');
if (!/^[a-zA-Z0-9_\-./~^@]+$/.test(ref)) {
throw new Error('invalid git ref');
}
const files = getGitDiffNumstat(ref); Defensive patterns
Strategy: validation
Validate before calling
function sanitizeGitRef(ref: unknown): string {
const s = String(ref ?? 'HEAD').trim().replace(/\\/g, '/');
if (!/^[a-zA-Z0-9_\-./~^@]+$/.test(s)) {
throw new Error(`ref contains unsafe characters: ${JSON.stringify(s)}`);
}
return s;
}
const safe = sanitizeGitRef(req.query.ref);
const files = getGitDiffNumstat(safe); Type guard
function isSafeGitRef(ref: string): boolean {
return typeof ref === 'string' && /^[a-zA-Z0-9_\-./~^@]+$/.test(ref) && ref.length <= 256;
} Try / catch
try {
return getGitDiffNumstat(ref);
} catch (e) {
if (/Invalid git ref/.test(String(e))) {
// Refused on purpose — do NOT mutate and retry. Surface to caller.
throw new Error(`rejected ref ${JSON.stringify(ref)}`);
}
throw e;
} Prevention
- Treat any user-supplied ref as untrusted — validate against the safe-character regex yourself.
- Prefer an allowlist of known refs (output of git branch --list) for user-facing inputs.
- Strip whitespace and normalize backslashes BEFORE validation.
- Never concatenate untrusted segments into a ref string.
When it happens
Trigger: Ref contains spaces, semicolons, pipes, backticks, $, (), {}, [], angle brackets, quotes, backslashes, commas, colons, or any other punctuation; a ref like 'origin/main;rm -rf /' or 'HEAD & cmd'; a ref built by string concatenation that picked up a stray space or newline.
Common situations: User-supplied ref from an HTTP query param or webhook payload passed unfiltered; ref read from a config file with trailing whitespace/newline; branch name containing a slash-separated team prefix that happens to include a blocked char; Windows ref string with a backslash path separator.
Related errors
- Invalid git ref: suspicious pattern
- Invalid container name: ${containerName}
- Dangerous key segment rejected: ${part}
- Key contains disallowed characters
- Namespace contains disallowed characters
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/0009d540dae1933e.
Report an issue: GitHub.