Skip to content

[Detail Bug] Repository ingestion logs are vulnerable to CRLF log injection via filenames #155

Description

@detail-app

Detail Bug Report

https://app.detail.dev/org_befd6425-a158-4e24-9d4d-1e5c08769515/bugs/bug_94b15bdf-7c97-469f-ad42-4e404757f3bf

Introduced in #10 by @WilliamAGH on Feb 6, 2026

Summary

  • Context: SourceCodeFileIngestionProcessor processes files from git repositories, logging each file's relative path at INFO level after successful chunking.
  • Bug: The relative path is logged without sanitization, allowing CRLF injection when filenames contain newline characters.
  • Actual vs. expected: Actual: filenames with CRLF are logged literally, enabling log line injection. Expected: newlines should be sanitized, matching the documented pattern in DocumentProcessor:281-283.
  • Impact: Repository content is untrusted input; malicious filenames can inject forged log lines visible in centralized logging.

Code with Bug

private void logProcessingComplete(
        int indexedDocumentCount, int totalChunkCount, String relativePath, long fileStartMillis) {
    long totalDuration = System.currentTimeMillis() - fileStartMillis;
    log.info(
            "Processed {}/{} chunks for {} in {}ms ({})",
            indexedDocumentCount,
            totalChunkCount,
            relativePath,  // <-- BUG 🔴 logged without sanitization (CR/LF can break log lines)
            totalDuration,
            progressTracker.formatPercent());
}

Explanation

  • relativePath originates from repository filenames (untrusted input). Git/GitHub allow filenames containing literal \r/\n, and such files survive clone + processing.
  • When a filename includes CRLF (e.g., test\r\nERROR.java), the INFO success log prints it verbatim, creating a forged additional log entry (“log injection”).
  • The issue affects the success path executed for every processed file; additional DEBUG/INFO statements in the same class also log relativePath unsanitized.

Codebase Inconsistency

DocumentProcessor already sanitizes provider-controlled fields before logging:

// The detail field can contain provider input, so logs retain only safe triage identifiers.
final String safeFailurePhase = failure.phase().replace('\r', '?').replace('\n', '?');
final String safeFailureFilePath = failure.filePath().replace('\r', '?').replace('\n', '?');
LOGGER.warn(LOG_FILE_FAILURE, safeFailurePhase, safeFailureFilePath);

SourceCodeFileIngestionProcessor does not apply similar sanitization to relativePath.

Exploit Scenario

An attacker (or compromised repo maintainer) adds a file to a repository with a name containing \r\n plus a crafted string that looks like a legitimate log entry (e.g., fake timestamp/level/message). When automated ingestion processes the repo, the success INFO log emits multiple physical log lines, injecting forged entries into centralized logging.

Recommended Fix

Sanitize relativePath before logging (and apply the same pattern to all log statements that include relativePath):

String safePath = relativePath.replace('\r', '?').replace('\n', '?');

Use safePath in the log arguments.

History

This bug was introduced in commit 499894a. The developer had fixed the identical CRLF injection vulnerability in DocumentProcessor 2 weeks earlier (commit a6f77e7, "fix(security): add path traversal protection and sanitize log output"), but failed to apply the same sanitization pattern when creating the new SourceCodeFileIngestionProcessor class for GitHub repository ingestion. The bug slipped in because the new processor was developed without reviewing existing security patterns in similar code paths.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions