Mintplex-Labs/anything-llm · error · Error

Invalid file path.

Error message

Invalid file path.

What it means

Thrown by renameLogoFile() when the uploaded logo's originalFilename, after normalizePath, resolves outside the assets directory. It is the path-traversal guard for the logo-upload pipeline: the original name is user-controlled (multer filename), so an attacker-supplied name carrying '..' or an absolute prefix is refused before fs.renameSync runs. The output filename is always a random uuid, so only the input side needs this check.

Source

Thrown at server/utils/files/logo.js:84

    found: true,
    buffer,
    size: buffer.length,
    mime,
  };
}

async function renameLogoFile(originalFilename = null) {
  const extname = path.extname(originalFilename) || ".png";
  const newFilename = `${v4()}${extname}`;
  const assetsDirectory = process.env.STORAGE_DIR
    ? path.join(process.env.STORAGE_DIR, "assets")
    : path.join(__dirname, `../../storage/assets`);
  const originalFilepath = path.join(
    assetsDirectory,
    normalizePath(originalFilename)
  );
  if (!isWithin(path.resolve(assetsDirectory), path.resolve(originalFilepath)))
    throw new Error("Invalid file path.");

  // The output always uses a random filename.
  const outputFilepath = process.env.STORAGE_DIR
    ? path.join(process.env.STORAGE_DIR, "assets", normalizePath(newFilename))
    : path.join(__dirname, `../../storage/assets`, normalizePath(newFilename));

  fs.renameSync(originalFilepath, outputFilepath);
  return newFilename;
}

async function removeCustomLogo(logoFilename = LOGO_FILENAME) {
  if (!logoFilename || !validFilename(logoFilename)) return false;
  const assetsDirectory = process.env.STORAGE_DIR
    ? path.join(process.env.STORAGE_DIR, "assets")
    : path.join(__dirname, `../../storage/assets`);

  const logoPath = path.join(assetsDirectory, normalizePath(logoFilename));
  if (!isWithin(path.resolve(assetsDirectory), path.resolve(logoPath)))

View on GitHub (pinned to 526360e320)

Solutions

  1. At the upload handler, strip the filename to its basename (path.basename) before passing to renameLogoFile.
  2. Reject filenames containing path separators or '..' at the multer filename resolver.
  3. Treat the thrown error as 400 and log the rejected filename for audit.
  4. Prefer letting the server generate the filename entirely and ignore the client-supplied original.

Example fix

// before
const newFile = await renameLogoFile(originalFilename); // originalFilename may be '../x.png'

// after
const safeName = path.basename(originalFilename || 'logo.png');
const newFile = await renameLogoFile(safeName);
Defensive patterns

Strategy: validation

Validate before calling

const safeName = path.basename(originalFilename || 'logo.png');
if (safeName.includes('..')) throw new UserError('Invalid filename', 400);

Type guard

function isBasenameOnly(v): v is string {
  return typeof v === 'string' && v === path.basename(v) && !v.includes('..');
}

Try / catch

try {
  await renameLogoFile(path.basename(originalFilename));
} catch (e) {
  if (e.message === 'Invalid file path.') return res.status(400).json({ error: e.message });
  throw e;
}

Prevention

When it happens

Trigger: A logo upload whose filename is '../../../etc/passwd', an absolute path like '/x.png', or contains backslash traversal on Windows. Reaching the guard means normalizePath did not fully neutralize the payload.

Common situations: A penetration test against the logo upload endpoint; a buggy client that sends the full local filesystem path as the filename header; charset-corrupted filenames from the upload pipeline.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13). Data as JSON: /api/errors/5f74606bc31d663c. Report an issue: GitHub.