CVE-2026-24047 Overview
A symlink attack vulnerability has been discovered in Backstage, an open framework for building developer portals. The resolveSafeChildPath utility function in @backstage/backend-plugin-api, which is designed to prevent path traversal attacks, fails to properly validate symlink chains and dangling symlinks. This allows attackers with low privileges to bypass path validation and access files outside designated directories.
Critical Impact
Attackers can exploit improper symlink validation to escape restricted directories, potentially accessing sensitive configuration files, credentials, or other backend data through the Scaffolder actions and backend components that rely on this function for path security.
Affected Products
- Backstage @backstage/backend-plugin-api versions prior to 0.1.17
- Backstage @backstage/cli-common (config loading functionality)
- Backstage developer portals using Scaffolder actions with file operations
Discovery Timeline
- 2026-01-21 - CVE CVE-2026-24047 published to NVD
- 2026-01-21 - Last updated in NVD database
Technical Details for CVE-2026-24047
Vulnerability Analysis
This vulnerability is classified as CWE-59 (Improper Link Resolution Before File Access), commonly known as a symlink attack. The core issue lies in the resolveSafeChildPath function's inability to properly resolve and validate complex symlink scenarios before performing file operations.
The vulnerability enables two distinct attack patterns: symlink chains and dangling symlinks. With symlink chains, an attacker creates a series of symbolic links (e.g., link1 → link2 → /outside) where intermediate symlinks eventually resolve to a path outside the allowed directory. With dangling symlinks, attackers create symbolic links pointing to non-existent paths outside the base directory, which would later be created during file operations.
This function is critical to the security architecture of Backstage as it's used by Scaffolder actions and other backend components to ensure file operations stay within designated directories. A successful exploit could allow an attacker to read sensitive files or write malicious content to arbitrary locations on the server filesystem.
Root Cause
The root cause is improper symlink resolution in the path validation logic. The original implementation used realpathSync directly without properly handling the case where intermediate symlinks in a chain could escape the allowed directory, or where dangling symlinks could point outside the base directory.
The vulnerable code in packages/backend-plugin-api/src/paths.ts relied on realpathSync from the fs module without implementing additional checks for symlink chains. The fix removes this direct dependency and implements a more robust resolution mechanism in packages/cli-common/src/isChildPath.ts.
Attack Vector
The attack requires network access and low-privilege authentication to interact with Backstage's Scaffolder functionality. An attacker who can create or modify templates could craft malicious symlinks that bypass the path validation:
- Create a symlink chain: link1 → link2 → /etc/passwd within an allowed directory
- When the resolveSafeChildPath function validates link1, it may fail to detect that the final resolution escapes the allowed path
- Subsequent file operations would then read from or write to the target outside the designated directory
// Security patch in packages/cli-common/src/isChildPath.ts
// Source: https://github.com/backstage/backstage/commit/ae4dd5d1572a4f639e1a466fd982656b50f8e692
import {
relative,
isAbsolute,
resolve as resolvePath,
dirname,
basename,
} from 'path';
import { realpathSync, lstatSync, readlinkSync } from 'fs';
// Resolves a path to its real location, following symlinks.
// Handles cases where the final target doesn't exist by recursively
// resolving parent directories.
function resolveRealPath(path: string): string {
try {
return realpathSync(path);
} catch (ex) {
if (ex.code !== 'ENOENT') {
throw ex;
}
}
// Check if path itself is a dangling symlink - recursively resolve the target
// to handle symlink chains (e.g., link1 -> link2 -> /outside)
try {
if (lstatSync(path).isSymbolicLink()) {
const target = resolvePath(dirname(path), readlinkSync(path));
// ... continued resolution logic
}
} catch (ex) {
// Handle resolution errors
}
}
Source: GitHub Commit ae4dd5d1572a4f639e1a466fd982656b50f8e692
Detection Methods for CVE-2026-24047
Indicators of Compromise
- Unexpected symbolic links appearing in Scaffolder working directories or template output paths
- File operations targeting paths outside designated Backstage working directories
- Creation of symlink chains within template directories
- Log entries showing file access attempts to sensitive system paths from Backstage processes
Detection Strategies
- Monitor filesystem events for symlink creation within Backstage working directories using auditd or similar tools
- Implement file integrity monitoring on critical system paths to detect unauthorized access
- Review Backstage application logs for path traversal patterns or unusual file operation errors
- Analyze template submissions for suspicious symlink references or chain patterns
Monitoring Recommendations
- Enable detailed logging for Scaffolder actions and file operations in Backstage
- Configure alerting on file access attempts outside expected Backstage directories
- Implement runtime application self-protection (RASP) to detect path traversal attempts
- Deploy SentinelOne Singularity to monitor for suspicious filesystem behavior and symlink manipulation patterns
How to Mitigate CVE-2026-24047
Immediate Actions Required
- Upgrade @backstage/backend-plugin-api to version 0.1.17 or later immediately
- Audit existing templates and Scaffolder output directories for suspicious symlinks
- Review access controls on template creation to ensure only trusted users can submit templates
- Implement network segmentation to limit Backstage server filesystem access
Patch Information
The vulnerability has been fixed in @backstage/backend-plugin-api version 0.1.17. The patch implements a robust resolveRealPath function that properly handles symlink chains and dangling symlinks by recursively resolving parent directories and validating each step of the symlink resolution chain.
For detailed patch information, see the GitHub Security Advisory GHSA-2p49-45hj-7mc9 and the commit ae4dd5d1572a4f639e1a466fd982656b50f8e692.
Workarounds
- Run Backstage in a containerized environment with limited filesystem access to minimize the impact of potential path traversal
- Restrict template creation permissions to trusted users only
- Implement strict file permission boundaries on the host filesystem to limit accessible paths
- Configure read-only mounts for sensitive system directories in containerized deployments
# Configuration example for containerized deployment with restricted filesystem
# Docker example limiting filesystem access for Backstage
docker run -d \
--name backstage \
--read-only \
--tmpfs /tmp \
--mount type=bind,source=/app/data,target=/app/data,readonly=false \
--cap-drop=ALL \
--security-opt=no-new-privileges \
backstage/backstage:latest
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

