ruvnet/ruflo · error · Error
Invalid git ref: suspicious pattern
Error message
Invalid git ref: suspicious pattern
What it means
Thrown by validateGitRef when the ref contains '..' (path-traversal indicator) but does NOT match the allowed range/range-abbrev patterns like 'a..b' or 'a..b' shorthand. Git ranges legitimately use '..' and '...' (e.g. 'main..feature', 'main...upstream'), so the validator permits those specific shapes and refuses anything else with double-dot — defending against '../' path escapes and '..@{-1}' style tricks.
Source
Thrown at v3/@claude-flow/cli/src/ruvector/diff-classifier.ts:378
// ============================================================================
// 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[] {
// SECURITY: Validate git ref to prevent command injection
validateGitRef(ref);
// Check cache first
const cacheKey = `numstat:${ref}`;View on GitHub (pinned to 6b01dc5a68)
Solutions
- If you intend a git range, use the canonical 'a..b' or 'a...b' form with simple branch names on each side.
- If the ref is meant as a path, reject '..' at the application layer and never let it reach git.
- Pre-validate with git rev-parse --verify <ref> in a sandbox to confirm the ref resolves before handing it to the diff tool.
Example fix
// before
const files = getGitDiffNumstat('../main');
// after — use canonical range syntax
const files = getGitDiffNumstat('main..feature'); Defensive patterns
Strategy: validation
Validate before calling
function asGitRange(a: string, b: string): string {
const clean = (s: string) => s.replace(/[^a-zA-Z0-9_\-.]/g, '');
return `${clean(a)}..${clean(b)}`; // canonical range, no traversal chars possible
}
const ref = asGitRange(baseBranch, featureBranch);
// passes validateGitRef because both sides match the range pattern
const files = getGitDiffNumstat(ref); Type guard
function isSafeGitRange(ref: string): boolean {
return /^[a-zA-Z0-9_\-]+\.\.\.?[a-zA-Z0-9_\-]+$/.test(ref);
} Try / catch
try {
return getGitDiffNumstat(ref);
} catch (e) {
if (/suspicious pattern/.test(String(e))) {
// The ref contains '..' but isn't a clean range. Refuse rather than rewrite —
// path traversal attempts must not be 'fixed' by normalization.
throw new Error(`refused suspicious ref: ${JSON.stringify(ref)}`);
}
throw e;
} Prevention
- Construct git ranges from two clean branch names with '..' or '...' — never join path-like segments.
- Reject any ref containing '../' at the application boundary; do not attempt to normalize it.
- For user input, resolve via git rev-parse --verify in a sandbox before passing to the diff tool.
When it happens
Trigger: Ref like '../secret' or '../../etc/passwd'; ref like 'foo..bar/baz/../x' mixing a range with traversal; ref like 'a..b..c' (more than one double-dot); a branch name someone literally created with '..' that isn't a clean range.
Common situations: Path-style ref ('../feature/foo') mistaken for a git range; ref constructed by joining path segments that included parent-dir traversal; branch name with '..' submitted via an API without normalization.
Related errors
- Key contains disallowed characters
- Namespace contains disallowed characters
- Invalid git ref: contains unsafe characters
- ${label} contains null bytes
- ${label} contains shell metacharacters
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/86893b0a56bbb3c5.
Report an issue: GitHub.