CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-24047

Backstage Pass: Breaking Out of the Sandbox with Symlinks

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 22, 2026·7 min read·20 visits

Executive Summary (TL;DR)

CVE-2026-24047 is a path traversal vulnerability in Backstage's `resolveSafeChildPath` function. It arises from improper validation of symbolic links when the target file does not yet exist. Attackers can chain symlinks to escape the intended directory boundary, potentially leading to Remote Code Execution (RCE) by overwriting configuration files or injecting malicious scripts.

A logic flaw in the Backstage framework's path resolution utility allowed attackers to bypass sandbox restrictions using symlinks to non-existent files. By exploiting how the system handled 'phantom' paths, malicious actors could escape the Scaffolder workspace and write files to arbitrary locations on the host filesystem.

The Hook: When Is a Path Not a Path?

Backstage is the darling of Platform Engineering. It's the "portal of portals," designed to unify your infrastructure tooling, services, and documentation into one slick UI. But under the hood, Backstage is doing a lot of heavy lifting—specifically via its Scaffolder. The Scaffolder is essentially a glorified remote file manipulation engine. It clones repos, templating files, moves things around, and pushes code. That sounds a lot like "RCE as a Service" if you aren't careful.

To keep this beast in a cage, Backstage relies on a utility function called resolveSafeChildPath. Its job is simple: ensure that whatever file operations the Scaffolder performs stay strictly within a temporary workspace. It's the bouncer at the club door, checking IDs to make sure no one sneaks into the VIP section (your /etc/shadow file or app-config.yaml).

But here's the thing about filesystems: they aren't just trees; they are graphs. Thanks to symbolic links (symlinks), a path like ./workspace/subdir can instantly teleport you to /root. CVE-2026-24047 is the story of how the bouncer got tricked by a ghost—specifically, how the system failed to validate paths that didn't exist yet.

The Flaw: Trusting the Non-Existent

The vulnerability lives in the gap between intention and reality. When you want to write a file, you usually check if the destination is safe before you write it. Backstage used Node.js's fs.realpathSync to resolve paths to their absolute location, ensuring they started with the safe base directory string.

This works great for files that exist. fs.realpathSync('/safe/base/../../etc/passwd') correctly resolves to /etc/passwd, and the check fails. But what happens if you try to resolve a path for a file you are about to create?

If you ask realpath to resolve /safe/base/symlink_to_root/new_file.txt, and new_file.txt doesn't exist yet, standard implementations often throw an ENOENT error or return the path partially resolved. Backstage's implementation failed to account for dangling symlinks or symlink chains where the final segment is missing.

Because the code couldn't "see" the final file (it wasn't there yet), it essentially shrugged and assumed the path was safe as long as the string manipulation looked okay. This is a classic Time-of-Check to Time-of-Use (TOCTOU) adjacent flaw. The code assumed that if it couldn't prove the path was bad, it must be good. In security, that is a fatal assumption.

The Code: The Smoking Gun

Let's look at the logic. The vulnerable code relied too heavily on the happy path of fs.realpathSync. When an ENOENT (File Not Found) error occurred, the validation logic became permissive or incomplete. It failed to walk up the directory tree to verify the parents.

Here is the corrected logic introduced in the patch (Commit ae4dd5d1). Notice the paranoia level has increased significantly. Instead of giving up when a file is missing, it recursively climbs the directory tree until it finds firm ground.

// The Fix: Recursive Resolution
function resolveRealPath(path: string): string {
  try {
    // 1. Try the standard resolution first
    return realpathSync(path);
  } catch (ex) {
    if (ex.code !== 'ENOENT') {
      throw ex;
    }
  }
 
  // 2. ALERT: The path doesn't exist. 
  // Check if the path ITSELF is a dangling symlink.
  try {
    if (lstatSync(path).isSymbolicLink()) {
      const target = resolvePath(dirname(path), readlinkSync(path));
      // RECURSION: Follow the white rabbit.
      return resolveRealPath(target);
    }
  } catch (ex) { /* ignore */ }
 
  // 3. The file is truly missing. 
  // We must verify the PARENT directory is safe.
  const parent = dirname(path);
  if (parent === path) return path; // Hit root
 
  // RECURSION: Resolve the parent, then append the missing child.
  return resolvePath(resolveRealPath(parent), basename(path));
}

> [!NOTE] > The Fix Strategy: The key change is that ENOENT is no longer an exit strategy. If the leaf node is missing, the code recursively resolves the parent. If parent turns out to be a symlink to /etc, resolveRealPath(parent) will return /etc, and the final check isChildPath('/safe/base', '/etc/new_file') will correctly return false.

The Exploit: Escaping the Matrix

To exploit this, we need to create a situation where we are writing to a file through a symlink, but the file doesn't exist yet so the check passes.

The Attack Scenario

Imagine we have a malicious Scaffolder template. Templates allow us to run shell scripts or file operations. We don't need root; we just need the ability to define a template.

Step 1: The Setup We define a step in our template that creates a symbolic link. This link points to a sensitive directory outside the workspace, like the application's config directory.

# Inside the workspace
ln -s /app/backstage-backend/ malicious_tunnel

Step 2: The Bypass Now, we instruct the Scaffolder to write a file through that tunnel. We ask it to create malicious_tunnel/pwned-config.yaml.

Step 3: The Execution

  1. Backstage calls resolveSafeChildPath('./malicious_tunnel/pwned-config.yaml').
  2. realpath looks for pwned-config.yaml. It's not there.
  3. The vulnerable code catches the ENOENT and fails to fully resolve malicious_tunnel because it was only looking at the full path's existence.
  4. The check passes: "Looks like a valid path inside the workspace!"
  5. The Scaffolder writes the file.
  6. Result: The file is actually written to /app/backstage-backend/pwned-config.yaml.

The Impact: Why Should You Care?

While the CVSS score is a "Medium" 6.3, don't let that fool you. In the right environment, this is a Critical issue. The CVSS metrics often underestimate the impact of file writes in developer tooling.

Configuration Overwrite: The most direct path to total compromise is overwriting app-config.yaml. An attacker could inject a new auth provider (e.g., allowing "guest" access) or change the database connection string to point to a malicious server to steal credentials.

RCE Potential: If the Backstage instance is running scheduled tasks (cron) or using dynamic imports, writing a file to the right place equates to Remote Code Execution. For example, overwriting a script in node_modules or a CI/CD pipeline definition could grant persistent access.

Data Corruption: Even without RCE, an attacker could simply trash the system by overwriting critical system files, causing a Denial of Service. The only thing saving most deployments is that Backstage is typically run as a non-root user (hopefully).

The Fix: Closing the Door

The remediation is straightforward: Update immediately.

Patch Details

  • Component: @backstage/backend-plugin-api
  • Fixed Version: 0.1.17

If you are using @backstage/cli-common directly in your own custom plugins to validate paths, ensure you have pulled the latest version containing commit ae4dd5d.

Defense in Depth

Don't just rely on the patch. This vulnerability highlights why application-level sandboxing is fragile.

  1. Container Hardening: Ensure your Backstage container runs with a Read-Only Root Filesystem, mounting only specific temporary directories as writable.
  2. User Permissions: Restrict who can register new templates in the Scaffolder. If guest users can run arbitrary templates, you are asking for trouble.
  3. Least Privilege: Never run Backstage as root. Ensure the OS user has write access only to the specific directories it needs.

Official Patches

BackstageGitHub Security Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
6.3/ 10
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Backstage ScaffolderBackstage Backend Plugins using `resolveSafeChildPath`Node.js applications using `@backstage/cli-common` for path validation

Affected Versions Detail

Product
Affected Versions
Fixed Version
@backstage/backend-plugin-api
Backstage
< 0.1.170.1.17
@backstage/cli-common
Backstage
< patched versionCommit ae4dd5d
AttributeDetail
CWE IDCWE-59 (Link Following)
CVSS v3.16.3 (Medium)
Attack VectorNetwork (via Scaffolder Templates)
ImpactArbitrary File Write / Potential RCE
Affected ComponentresolveSafeChildPath
Fix Commitae4dd5d1572a4f639e1a466fd982656b50f8e692

MITRE ATT&CK Mapping

T1566Phishing (via malicious Template)
Initial Access
T1059Command and Scripting Interpreter
Execution
T1202Indirect Command Execution (via Config Overwrite)
Defense Evasion
CWE-59
Link Following

Improper Link Resolution Before File Access ('Link Following')

Known Exploits & Detection

HypotheticalExploitation involves creating a Scaffolder template that symlinks to a sensitive directory and writes a new file through that link.

Vulnerability Timeline

Fix committed to master
2026-01-20
CVE Published / Advisory Released
2026-01-21

References & Sources

  • [1]GHSA Advisory
  • [2]NVD Entry

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 8 hours ago•CVE-2022-0492
7.8

CVE-2022-0492: Privilege Escalation and Container Escape via cgroups v1 release_agent

CVE-2022-0492 is a high-severity missing authorization vulnerability in the Linux kernel's Control Groups (cgroups) v1 implementation. The flaw resides within the cgroup_release_agent_write function in kernel/cgroup/cgroup-v1.c, where the kernel fails to validate if the process writing to the release_agent file possesses administrative capabilities in the initial user namespace. This allows a local attacker inside a container with root privileges (UID 0) to abuse user namespaces, mount a cgroups v1 directory, modify the release_agent parameter, and execute arbitrary commands on the host system as host root, effectively achieving a complete container escape.

Amit Schendel
Amit Schendel
5 views•7 min read
•2 days ago•GHSA-G72G-R7M4-9X4G
6.3

GHSA-G72G-R7M4-9X4G: Insufficient Session Expiration of OAuth Tokens in NocoDB

NocoDB is subject to an insufficient session expiration vulnerability where OAuth access and refresh tokens are not invalidated or revoked during security-sensitive actions such as password changes, forgot-password requests, or password resets. This allows an attacker possessing an active OAuth token to maintain unauthorized persistence.

Amit Schendel
Amit Schendel
8 views•6 min read
•2 days ago•GHSA-FGMC-2HQJ-86V4
6.9

GHSA-FGMC-2HQJ-86V4: Default Administrative Credentials in vantage6-server

A vulnerability in the vantage6 federated learning framework allows unauthenticated remote attackers to gain administrative control of the server via hardcoded default credentials (root/root) when deployed under default configurations in versions 4.2.3 and below.

Amit Schendel
Amit Schendel
8 views•5 min read
•2 days ago•GHSA-X9F6-9RVM-MMRG
6.9

GHSA-X9F6-9RVM-MMRG: Improper Access Control and Volume Mount Isolation Bypass in vantage6 Node

An improper access control vulnerability in the vantage6 node component allows concurrently running algorithm containers to read and modify sensitive input and output files of other tasks. The lack of strict workspace directory isolation exposes a significant attack surface in multi-tenant or federated environments where untrusted algorithms are executed.

Amit Schendel
Amit Schendel
3 views•4 min read
•2 days ago•CVE-2026-47760
8.7

CVE-2026-47760: Cross-Site Scripting (XSS) via SVG Namespace Sanitizer Bypass in TinyMCE

TinyMCE versions 6.8.0 through 7.0.1 contain a high-severity Cross-Site Scripting (XSS) vulnerability. The flaw exists in the custom HTML parser and sanitizer module, which incorrectly manages SVG namespace scopes when parsing nested elements. A low-privileged or unauthenticated attacker can submit a crafted HTML payload containing nested SVG structures to bypass sanitization filters, leading to arbitrary JavaScript execution in the context of the victim's browser session.

Alon Barad
Alon Barad
27 views•7 min read
•2 days ago•CVE-2026-47759
8.7

CVE-2026-47759: Stored Cross-Site Scripting (XSS) via Unsanitized data-mce-* Serialization Bypass in TinyMCE

CVE-2026-47759 is a critical stored Cross-Site Scripting (XSS) vulnerability affecting multiple active branches of the TinyMCE rich text editor. The flaw resides in the editor's handling of user-controlled, prefixed internal attributes, such as data-mce-href, data-mce-src, and data-mce-style. When processing raw HTML inputs, TinyMCE's internal validation schema neglects to inspect these custom prefixed attributes. During HTML serialization, the editor's engine extracts these unsanitized values and copies them back into standard executable attributes, overwriting any previously sanitized standard values and leading to execution of arbitrary code.

Amit Schendel
Amit Schendel
13 views•7 min read