diff --git a/packages/fx-core/src/component/driver/teamsApp/utils/ManifestUtils.ts b/packages/fx-core/src/component/driver/teamsApp/utils/ManifestUtils.ts index c24b5e496e..c6917d4b59 100644 --- a/packages/fx-core/src/component/driver/teamsApp/utils/ManifestUtils.ts +++ b/packages/fx-core/src/component/driver/teamsApp/utils/ManifestUtils.ts @@ -463,6 +463,12 @@ export class ManifestUtils { maxLength = 25 ): Promise> { const manifestPath = this.getTeamsAppManifestPath(projectPath); + const resolvedProjectPath = path.resolve(projectPath); + const resolvedManifestPath = path.resolve(manifestPath); + const relative = path.relative(resolvedProjectPath, resolvedManifestPath); + if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) { + return ok(undefined); + } if (fs.pathExistsSync(manifestPath)) { const manifest = (await fs.readJson(manifestPath)) as TeamsAppManifest; const shortName = manifest.name.short; diff --git a/packages/fx-core/src/component/utils/settingsUtil.ts b/packages/fx-core/src/component/utils/settingsUtil.ts index 3044949e6d..43ab4841ab 100644 --- a/packages/fx-core/src/component/utils/settingsUtil.ts +++ b/packages/fx-core/src/component/utils/settingsUtil.ts @@ -3,6 +3,7 @@ import { err, FxError, ok, Result, Settings } from "@microsoft/teamsfx-api"; import * as fs from "fs-extra"; +import * as path from "path"; import * as uuid from "uuid"; import { parseDocument } from "yaml"; import { featureFlagManager, FeatureFlags } from "../../common/featureFlags"; @@ -17,6 +18,13 @@ import { FileNotFoundError } from "../../error/common"; import { pathUtils } from "./pathUtils"; class SettingsUtils { + private isPathWithinDirectory(baseDir: string, targetPath: string): boolean { + const resolvedBase = path.resolve(baseDir); + const resolvedTarget = path.resolve(targetPath); + const relative = path.relative(resolvedBase, resolvedTarget); + return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative); + } + async readSettings( projectPath: string, ensureTrackingId = true @@ -37,7 +45,9 @@ class SettingsUtils { const projectId = uuid.v4(); const projectIdField = appYaml.createPair("projectId", uuid.v4()); appYaml.add(projectIdField); - await fs.writeFile(projectYamlPath, appYaml.toString()); // only write yaml file once instead of write yaml file after every command + if (this.isPathWithinDirectory(projectPath, projectYamlPath)) { + await fs.writeFile(projectYamlPath, appYaml.toString()); + } sendTelemetryEvent(Component.core, TelemetryEvent.FillProjectId, { [TelemetryProperty.ProjectId]: projectId, }); @@ -50,6 +60,7 @@ class SettingsUtils { globalVars.trackingId = projectSettings.trackingId; // set trackingId to globalVars return ok(projectSettings); } + async writeSettings(projectPath: string, settings: Settings): Promise> { let projectYamlPath: string | undefined; if (featureFlagManager.getBooleanValue(FeatureFlags.GenerateConfigFiles)) { @@ -64,7 +75,9 @@ class SettingsUtils { const yamlFileContent: string = await fs.readFile(projectYamlPath, "utf8"); const appYaml = parseDocument(yamlFileContent); appYaml.set("projectId", settings.trackingId); - await fs.writeFile(projectYamlPath, appYaml.toString()); + if (this.isPathWithinDirectory(projectPath, projectYamlPath)) { + await fs.writeFile(projectYamlPath, appYaml.toString()); + } return ok(projectYamlPath); } } diff --git a/packages/fx-core/tests/component/driver/teamsApp/manifestUtils.test.ts b/packages/fx-core/tests/component/driver/teamsApp/manifestUtils.test.ts index 27fb32cea7..e452b4fc32 100644 --- a/packages/fx-core/tests/component/driver/teamsApp/manifestUtils.test.ts +++ b/packages/fx-core/tests/component/driver/teamsApp/manifestUtils.test.ts @@ -521,6 +521,17 @@ describe("trimManifestShortName", () => { assert.isTrue(readJsonStub.notCalled); assert.isTrue(writeFileStub.notCalled); }); + it("Skips paths outside project directory", async () => { + const teamsManifest = new TeamsAppManifest(); + teamsManifest.name.short = "shortname abcdefghijklmnopqrstuvwxyz${{APP_NAME_SUFFIX}}"; + const readJsonStub = sandbox.stub(fs, "readJson").resolves(teamsManifest); + const writeFileStub = sandbox.stub(fs, "writeFile").resolves(); + sandbox.stub(fs, "pathExistsSync").returns(true); + const res = await manifestUtils.trimManifestShortName("/some/other/path"); + assert.isTrue(res.isOk()); + assert.isTrue(readJsonStub.notCalled); + assert.isTrue(writeFileStub.notCalled); + }); }); describe("resolveLocFile", () => {