angular/angular-cli · warning

Detected a potential path traversal attempt in '${pkgJsonPat

Error message

Detected a potential path traversal attempt in '${pkgJsonPath}'. The path '${bestPracticesInfo.path}' escapes the package boundary. Falling back to the bundled guide.

What it means

After resolving @angular/core's package.json, the tool computes the guide file's path and verifies it stays inside the package directory using a path.relative check (relative path must not start with '..' nor be absolute). If the resolved path escapes the package boundary — a potential path traversal — the tool warns and falls back to the bundled guide instead of reading the file.

Source

Thrown at packages/angular/cli/src/commands/mcp/tools/best-practices.ts:153

  try {
    const pkgJsonContent = await readFile(pkgJsonPath, 'utf-8');
    const pkgJson = JSON.parse(pkgJsonContent);
    const bestPracticesInfo = pkgJson['angular']?.bestPractices;

    if (
      bestPracticesInfo &&
      bestPracticesInfo.format === 'markdown' &&
      typeof bestPracticesInfo.path === 'string'
    ) {
      const packageDirectory = dirname(pkgJsonPath);
      const guidePath = resolve(packageDirectory, bestPracticesInfo.path);

      // Ensure the resolved guide path is within the package boundary.
      // Uses path.relative to create a cross-platform, case-insensitive check.
      // If the relative path starts with '..' or is absolute, it is a traversal attempt.
      const relativePath = relative(packageDirectory, guidePath);
      if (relativePath.startsWith('..') || isAbsolute(relativePath)) {
        logger.warn(
          `Detected a potential path traversal attempt in '${pkgJsonPath}'. ` +
            `The path '${bestPracticesInfo.path}' escapes the package boundary. ` +
            'Falling back to the bundled guide.',
        );

        return undefined;
      }

      // Check the file size to prevent reading a very large file.
      const stats = await stat(guidePath);
      if (stats.size > 1024 * 1024) {
        // 1MB
        logger.warn(
          `The best practices guide at '${guidePath}' is larger than 1MB (${stats.size} bytes). ` +
            'This is unexpected and the file will not be read. Falling back to the bundled guide.',
        );

        return undefined;

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Reinstall dependencies (`npm ci`) to restore an untampered @angular/core package.
  2. Check node_modules/@angular/core for unexpected symlinks or modified package.json path fields.
  3. Audit installed package versions against the npm registry; rely on the bundled guide until resolved.
Defensive patterns

Strategy: validation

Validate before calling

import { relative, isAbsolute, resolve } from 'node:path';
function isInsidePackage(pkgDir: string, target: string): boolean {
  const rel = relative(resolve(pkgDir), resolve(target));
  return !rel.startsWith('..') && !isAbsolute(rel);
}
if (!isInsidePackage(packageDirectory, guidePath)) {
  console.warn('Resolved path escapes package boundary; use bundled guide.');
}

Try / catch

try {
  assertInsidePackage(packageDirectory, guidePath);
} catch {
  return bundledGuide(); // safe fallback on traversal attempt
}

Prevention

When it happens

Trigger: The path recorded in @angular/core's package.json (e.g. a guide path field) resolves outside the package directory — tampered/malicious package, symlink escapes, or an unusual package layout on case-insensitive filesystems.

Common situations: Compromised or patched node_modules packages; packages with symlinks pointing outside their directory; custom/renamed @angular/core forks with unexpected path fields.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/367ad9bf81dd5e5a. Report an issue: GitHub.