usebruno/bruno · error · Error

Access to files outside of the collectionPath is not…

Error message

Access to files outside of the collectionPath is not allowed.

What it means

Thrown by the QuickJS local-module loader shim when the resolved path of a required local file escapes the collectionPath. The check uses path.relative: if the relative path starts with '..' or is absolute, the require is rejected. This is a security guard preventing sandboxed scripts from reading arbitrary host files.

Solutions

  1. Move the needed file inside the current collection directory and require it with a relative path that stays under collectionPath.
  2. If sharing across collections, copy or symlink the helper into the collection.
  3. Never interpolate untrusted values into require() paths.

Example fix

// before
const helper = require('../../shared/helper'); // escapes collection

// after — copy helper into the collection
const helper = require('./shared/helper');
Defensive patterns

Strategy: validation

Validate before calling

const path = require('path');
function isInsideCollection(target, root) {
  const rel = path.relative(root, path.resolve(root, target));
  return !rel.startsWith('..') && !path.isAbsolute(rel);
}
if (!isInsideCollection(reqPath, bru.cwd())) throw new Error('path outside collection');

Type guard

const isSafeRelativePath = (p, root) => { const rel = path.relative(root, path.resolve(root, p)); return !rel.startsWith('..') && !path.isAbsolute(rel); };

Try / catch

try { const m = require(maybeUnsafePath); }
catch (err) {
  if (/outside of the collectionPath/.test(err.message)) {
    // use a copy of the file inside the collection instead
  } else throw err;
}

Prevention

When it happens

Trigger: require('../../../etc/passwd'), require('/etc/secrets'), or require('../../other-collection/file') inside a QuickJS-sandboxed Bru script where the resolved absolute path is not within the collection directory tree.

Common situations: A shared helper legitimately lives in a sibling collection and the developer tries to reach it via ../; an imported snippet contains a path-traversal string; a variable interpolated into require() yields an unexpected absolute path.

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/85328d02b4e8162b. Report an issue: GitHub.

Appendix: source

Thrown at packages/bruno-js/src/sandbox/quickjs/shims/local-module.js:19

const path = require('path');
const fs = require('fs');
const { marshallToVm } = require('../utils');

const addLocalModuleLoaderShimToContext = (vm, collectionPath) => {
  let loadLocalModuleHandle = vm.newFunction('loadLocalModule', function (module) {
    const filename = vm.dump(module);

    // Check if the filename has an extension
    const hasExtension = path.extname(filename) !== '';
    const resolvedFilename = hasExtension ? filename : `${filename}.js`;

    // Resolve the file path and check if it's within the collectionPath
    const filePath = path.resolve(collectionPath, resolvedFilename);
    const relativePath = path.relative(collectionPath, filePath);

    // Ensure the resolved file path is inside the collectionPath
    if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
      throw new Error('Access to files outside of the collectionPath is not allowed.');
    }

    if (!fs.existsSync(filePath)) {
      throw new Error(`Cannot find module ${filename}`);
    }

    let code = fs.readFileSync(filePath).toString();

    return marshallToVm(code, vm);
  });

  vm.setProp(vm.global, '__brunoLoadLocalModule', loadLocalModuleHandle);
  loadLocalModuleHandle.dispose();
};

module.exports = addLocalModuleLoaderShimToContext;

View on GitHub (pinned to 9bdd81c7bd)