VYPR
Medium severity5.8NVD Advisory· Published Oct 3, 2024· Updated Apr 15, 2026

CVE-2024-47762

CVE-2024-47762

Description

Backstage is an open framework for building developer portals. Configuration supplied through APP_CONFIG_* environment variables, for example APP_CONFIG_backend_listen_port=7007, where unexpectedly ignoring the visibility defined in configuration schema. This occurred even if the configuration schema specified that they should have backend or secret visibility. This was an intended feature of the APP_CONFIG_* way of supplying configuration, but now clearly goes against the expected behavior of the configuration system. This behavior leads to a risk of potentially exposing sensitive configuration details intended to remain private or restricted to backend processes. The issue has been resolved in version 0.3.75 of the @backstage/plugin-app-backend package. As a temporary measure, avoid supplying secrets using the APP_CONFIG_ configuration pattern. Consider alternative methods for setting secrets, such as the environment substitution available for Backstage configuration.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@backstage/plugin-app-backendnpm
< 0.3.750.3.75

Patches

1
323e6129073c

Merge pull request #26950 from backstage/fix-app-config-env-variable

https://github.com/backstage/backstagePatrik OldsbergOct 3, 2024via ghsa
3 files changed · +108 6
  • .changeset/friendly-coins-approve.md+5 0 added
    @@ -0,0 +1,5 @@
    +---
    +'@backstage/plugin-app-backend': patch
    +---
    +
    +Fixed unexpected behaviour where configuration supplied with `APP_CONFIG_*` environment variables where not filtered by the configuration schema.
    
  • plugins/app-backend/src/lib/config/readFrontendConfig.test.ts+99 0 added
    @@ -0,0 +1,99 @@
    +/*
    + * Copyright 2024 The Backstage Authors
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +
    +import { createMockDirectory } from '@backstage/backend-test-utils';
    +import { readFrontendConfig } from './readFrontendConfig';
    +import { ConfigReader } from '@backstage/config';
    +
    +describe('readFrontendConfig', () => {
    +  const mockDir = createMockDirectory();
    +
    +  afterEach(() => {
    +    mockDir.clear();
    +  });
    +
    +  it('should validate env config', async () => {
    +    mockDir.setContent({
    +      'appDir/.config-schema.json': JSON.stringify({
    +        schemas: [
    +          {
    +            value: {
    +              type: 'object',
    +
    +              properties: {
    +                app: {
    +                  type: 'object',
    +                  properties: {
    +                    secretOfLife: {
    +                      type: 'string',
    +                      visibility: 'secret',
    +                    },
    +                    backendConfig: {
    +                      type: 'string',
    +                      visibility: 'backend',
    +                    },
    +                    publicValue: {
    +                      type: 'string',
    +                      visibility: 'frontend',
    +                    },
    +                  },
    +                },
    +              },
    +            },
    +          },
    +        ],
    +        backstageConfigSchemaVersion: 1,
    +      }),
    +    });
    +
    +    const config = new ConfigReader({
    +      app: {
    +        secretOfLife: '42',
    +        backendConfig: 'backend',
    +        publicValue: 'public',
    +      },
    +    });
    +
    +    const frontendConfig = await readFrontendConfig({
    +      env: {
    +        APP_CONFIG_app_secretOfLife: 'ignored',
    +        APP_CONFIG_app_backendConfig: 'ignored',
    +        APP_CONFIG_app_publicValue: 'injected',
    +      },
    +      appDistDir: `${mockDir.path}/appDir`,
    +      config,
    +    });
    +
    +    expect(frontendConfig).toEqual([
    +      {
    +        context: 'env',
    +        data: {
    +          app: {
    +            publicValue: 'injected',
    +          },
    +        },
    +        deprecatedKeys: [],
    +        filteredKeys: undefined,
    +      },
    +      {
    +        context: 'app',
    +        data: { app: { publicValue: 'public' } },
    +        deprecatedKeys: [],
    +        filteredKeys: undefined,
    +      },
    +    ]);
    +  });
    +});
    
  • plugins/app-backend/src/lib/config/readFrontendConfig.ts+4 6 modified
    @@ -36,10 +36,9 @@ export async function readFrontendConfig(options: {
     }): Promise<AppConfig[]> {
       const { env, appDistDir, config } = options;
     
    -  const appConfigs = readEnvConfig(env);
    -
       const schemaPath = resolvePath(appDistDir, '.config-schema.json');
       if (await fs.pathExists(schemaPath)) {
    +    const envConfigs = readEnvConfig(env);
         const serializedSchema = await fs.readJson(schemaPath);
     
         try {
    @@ -49,11 +48,10 @@ export async function readFrontendConfig(options: {
               serialized: serializedSchema,
             }));
     
    -      const frontendConfigs = await schema.process(
    -        [{ data: config.get() as JsonObject, context: 'app' }],
    +      return await schema.process(
    +        [...envConfigs, { data: config.get() as JsonObject, context: 'app' }],
             { visibility: ['frontend'], withDeprecatedKeys: true },
           );
    -      appConfigs.push(...frontendConfigs);
         } catch (error) {
           throw new Error(
             'Invalid app bundle schema. If this error is unexpected you need to run `yarn build` in the app. ' +
    @@ -63,5 +61,5 @@ export async function readFrontendConfig(options: {
         }
       }
     
    -  return appConfigs;
    +  return [];
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.