Oct 7, 2026·6 min read·4 visits
Authenticated users can extract raw, unredacted backend-managed credentials from task failure logs and database events generated by failed Backstage Scaffolder workflows.
The @backstage/plugin-scaffolder-backend package prior to version 4.1.0 is vulnerable to sensitive information exposure in Scaffolder task failure events. Under specific template and failure conditions, an authenticated user can retrieve backend-managed credentials, such as VCS access tokens and API keys, from affected task execution events and stored database logs. This vulnerability has been remediated in version 4.1.0 of the package and is bundled with the Backstage platform release v1.54.6.
The Backstage Open-Source Developer Portal Framework provides a Software Templates feature (the Scaffolder) to automate infrastructure provisioning and codebase bootstrap tasks. This functionality is managed by the @backstage/plugin-scaffolder-backend package, which coordinates step-by-step actions like cloning repositories, creating directories, and registering catalog entities.
To perform operations on behalf of users or the organization, the Scaffolder backend requires access to backend-managed secrets. These secrets include personal access tokens (PATs) for version control platforms like GitHub or GitLab, as well as cloud platform access keys.
Prior to version 4.1.0, a vulnerability existed in the error handling and logging paths of the Scaffolder execution engine. Under certain conditions, when a template execution step or persistence checkpoint failed, the backend leaked the secrets used during task execution into the task's failure events. These unredacted events were recorded in the backend database and exposed to authenticated users via the Scaffolder API.
The underlying flaw resides in how the NunjucksWorkflowRunner and the associated Winston logging mechanism managed exceptions. In the event of a step failure, the workflow runner caught the raw error object thrown by the step and serialized it into the database via the taskTrack.markFailed(step, err) method.
Because Node.js Error objects, third-party API client exceptions, and database errors often preserve input parameters within their message or stack trace strings, the unredacted secrets were written directly into the DB. This bypasses the typical stdout/stderr logging layers that might otherwise apply basic masking rules.
Furthermore, several specific design factors exacerbated the leak:
Checkpoint Failures: If checkpoint state updates failed, the system stringified the raw error via stringifyError(err) without invoking log-redaction filters.
AggregateError Traps: When multiple parallel actions or actions combined with checkpoint updates failed, the runtime raised an AggregateError. Native JavaScript AggregateError objects retain their constituent error payloads in an internal .errors array. Standard redaction systems that operate on top-level properties missed these deeply nested child errors.
Transformation Gaps: The Winston log redacter used basic key-value equality to build redaction lists. If a template transformed a secret (such as changing uppercase or lowercase using Nunjucks filters like ${{ secrets.token | upper }}), the redacter could not correlate the transformed token with the original secret representation, allowing the transformed secret to bypass validation filters.
An analysis of the patch in commit 3f1e869708f002fb9838624b7379deb251691b47 reveals the precise architectural changes made to mitigate this exposure.
In plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts, the exception handling was modified to actively redact the caught errors before passing them to the state recorder:
// Before Patch
} catch (err) {
await taskTrack.markFailed(step, err);
await stepTrack.markFailed();
throw err;
}
// After Patch
} catch (cause) {
const err = taskLogger.redactError(cause);
await taskTrack.markFailed(step, err);
await stepTrack.markFailed();
throw err;
}The implementation of redactError in logger.ts was rewritten to sanitize errors. Instead of modifying the error object in-place, which could leave nested fields intact, the patch creates a brand-new, sterile error replica holding only sanitized name, message, and stack properties:
const redactError = (error: unknown): ErrorLike => {
if ((typeof error !== 'object' || error === null) && typeof error !== 'function') {
return typeof error === 'string'
? createSanitizedError('Error', redact(error))
: createUnknownError(error);
}
const errorLike = error as Partial<ErrorLike>;
let originalName: unknown;
let originalMessage: unknown;
let originalStack: unknown;
try {
originalName = errorLike.name;
originalMessage = errorLike.message;
originalStack = errorLike.stack;
} catch {
return createSanitizedError(); // Safe fallback for throwing getters
}
if (typeof originalName !== 'string' || !originalName || typeof originalMessage !== 'string') {
return createUnknownError(error);
}
const name = redact(originalName);
const message = redact(originalMessage);
const stack = typeof originalStack === 'string' ? redact(originalStack) : undefined;
return createSanitizedError(name, message, stack);
};This defensive approach effectively strips out any non-standard metadata, custom error attributes, or nested prototype properties, preventing data leaks from alternative object fields.
In terms of completeness, this fix is highly robust. By detaching custom attributes and recreating a standardized object rather than attempting to recursively filter unknown nested fields, the patch addresses both the AggregateError issue and any potential exploitation involving custom getter functions on error objects.
To exploit this vulnerability, an attacker must have authenticated access to the Backstage instance with permissions sufficient to register a template, trigger a template run, or read the event log of an existing task.
An attacker can trigger this information leak by crafting a software template that deliberately forces a failure within an action executing with elevated credentials.
For example, an attacker can define a step that relies on a secret but targets an invalid endpoint or provides bad parameters to a CLI execution. When the step fails, the action handler raises an exception containing the evaluated secret parameter. This unredacted string is written directly to the task_events database.
The attacker then makes an authorized HTTP request to the Scaffolder events endpoint for that specific task: /api/scaffolder/v2/tasks/<task_id>/events. The response contains the raw execution logs, including the error object fields containing the plain-text credentials.
The security impact of this vulnerability is classified as Medium. Although it leads to high confidentiality compromise (C:H), exploitation is restricted by attack complexity and privileges required. The attacker must possess authenticated access to the Backstage platform and the ability to trigger or monitor specific Scaffolder tasks.
Despite the Medium CVSS rating, the operational risk remains significant. The credentials stored in Backstage software templates typically belong to high-privilege service accounts or organization-wide deploy tokens. Exfiltration of these tokens can allow attackers to bypass standard access controls on Git repositories, enabling supply chain attacks or giving them the ability to write malicious code to production branches.
Remediation requires upgrading the @backstage/plugin-scaffolder-backend package or the overarching Backstage release.
Because task events are stored in the database, upgrading the software prevents future leaks but does not delete historical records. Security teams should run cleanup scripts to purge potentially leaked secrets from the database.
For teams unable to patch immediately, temporary mitigations include implementing strict access controls on the task events API and monitoring database event tables for standard credential regular expressions.
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@backstage/plugin-scaffolder-backend Backstage | < 4.1.0 | 4.1.0 |
Backstage (Core Repository) Backstage | < v1.54.6 | v1.54.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-532 |
| Attack Vector | Network (AV:N) |
| CVSS Base Score | 5.3 |
| EPSS Score | 0.00284 |
| Impact | High Confidentiality Loss (C:H) |
| Exploit Status | none |
| CISA KEV Status | Not Listed |
The product writes sensitive information to log files, making it retrieveable by individuals who have read access to the logs or events database.
A critical remote code execution vulnerability was identified in WeasyPrint prior to version 70.0. When compiling HTML containing a malicious Encapsulated PostScript (EPS) graphic on a host with Ghostscript installed, Pillow invokes Ghostscript to process the image, executing arbitrary PostScript commands.
An authorization bypass vulnerability in the Spotify Backstage TechDocs backend plugin allows authenticated attackers with access to at least one valid TechDocs site to read arbitrary static documentation from other entities. This occurs due to un-sanitized relative subpaths passing directly to external storage drivers.
A critical security flaw exists in PraisonAI before version 4.6.78 when operating in AgentMail webhook mode. The application processes incoming POST requests without checking for cryptographic signatures, allowing unauthenticated attackers to forge emails, spoof identities, and force AI agents to execute unauthorized operations.
A missing authorization vulnerability (CWE-862) exists in praisonai-platform versions prior to 0.1.9, allowing low-privileged workspace members to delete planning dependencies on issues owned by administrators by routing the deletion request through an attacker-owned issue.
CVE-2026-46438 is a critical Broken Object Level Authorization (BOLA) / Insecure Direct Object Reference (IDOR) vulnerability identified in the wger fitness manager prior to version 2.6. An authenticated attacker can exploit a missing authorization check on the slot_entry API parameter to inject unauthorized workout logs into another user's training schedule. This results in the corruption of the target user's automated progressive-overload calculations.
CVE-2026-105795 (GHSA-6gw6-rv2g-25mg) is a critical path traversal vulnerability in Microsoft Kiota, an OpenAPI-based HTTP client and plugin manifest generator. In affected versions (1.25.1 to < 1.35.0), Kiota propagates the unvalidated `x-ai-capabilities.response_semantics.oauth_card_path` vendor extension directly into generated API plugin manifests, leading to potential path traversal exploitation by downstream consumers.