Skip to content

fix(security): add path traversal validation to widget save path (GHSA-r553-q33m-v7pf)#41834

Open
subrata71 wants to merge 2 commits into
releasefrom
fix/widget-path-traversal-ghsa-r553-q33m-v7pf
Open

fix(security): add path traversal validation to widget save path (GHSA-r553-q33m-v7pf)#41834
subrata71 wants to merge 2 commits into
releasefrom
fix/widget-path-traversal-ghsa-r553-q33m-v7pf

Conversation

@subrata71
Copy link
Copy Markdown
Collaborator

@subrata71 subrata71 commented May 21, 2026

Description

Fixes the path traversal vulnerability in Git widget serialization reported in GHSA-r553-q33m-v7pf.

Root cause: FileUtilsCEImpl.updateEntitiesInRepo() writes widget files to disk using user-controlled widgetName values without calling validatePathIsWithinGitRoot(). All other Git file write helpers in the same class (saveResource(), saveActions(), saveActionCollection(), saveResourceCommon()) already validate paths, but the widget save path was the only one that skipped this check.

Attack: An authenticated user with edit access to a Git-connected application can set widgetName to a path traversal payload (e.g., ../../../../tmp/evil) via the layout update API. When Git serialization is triggered (status/commit/auto-commit), the widget JSON is written outside the Git repository to an arbitrary location on the server filesystem.

Fix: Add validatePathIsWithinGitRoot() calls on both the widget directory path and the final file path before calling fileOperations.saveWidgets(), consistent with the established pattern used by every other write helper in FileUtilsCEImpl.

Fixes

Testing

  • Added regression test: saveApplicationRef_pathTraversalInWidgetName_throwsSecurityException_GHSA_r553 — constructs a DSL with a path traversal widget name, verifies AppsmithPluginException is thrown, verifies no file is created outside git root
  • Added positive test: saveApplicationRef_legitimateWidgetName_doesNotThrow_GHSA_r553 — verifies legitimate widget names still serialize correctly
  • Full appsmith-git test suite: 72/72 tests pass
  • Full server compilation: clean

CE/EE Impact

CE-only change. The EE FileUtilsImpl calls super.updateEntitiesInRepo() so the fix propagates automatically. No EE-specific changes needed.

Warning

Tests have not run on the HEAD eff0ba7 yet


Thu, 21 May 2026 14:02:56 UTC

Summary by CodeRabbit

  • Bug Fixes

    • Added path validation when saving applications to Git repositories, preventing unauthorized file access during the save process.
  • Tests

    • Added security tests verifying path validation correctly handles both legitimate and malicious widget names during application serialization.

Review Change Stack

subrata71 added 2 commits May 21, 2026 19:59
…-v7pf)

Adds regression tests that verify:
- Widget names containing path traversal sequences (e.g., "../../../../tmp/evil")
  are rejected during Git serialization with a security exception
- Legitimate widget names continue to serialize correctly
…A-r553-q33m-v7pf)

The widget serialization path in FileUtilsCEImpl.updateEntitiesInRepo()
wrote files using user-controlled widgetName values without calling
validatePathIsWithinGitRoot(), while all other Git write helpers in
the same class did. An authenticated user with edit access to a
Git-connected application could craft a widgetName containing path
traversal sequences to write arbitrary JSON files outside the Git
repository on the server filesystem.

Add validatePathIsWithinGitRoot() calls on both the widget directory
path and the final file path before calling saveWidgets(), consistent
with how saveResource(), saveActions(), and saveActionCollection()
already validate their paths.
@subrata71 subrata71 requested a review from a team as a code owner May 21, 2026 14:02
@subrata71 subrata71 added the Security Issues related to information security within the product label May 21, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Walkthrough

This PR adds path traversal defense-in-depth to widget file serialization in the Appsmith git module. The implementation validates widget paths against the configured git root before write operations, and new security tests confirm that malicious widget names are rejected while legitimate names serialize correctly.

Changes

Path traversal validation in widget serialization (GHSA-r553)

Layer / File(s) Summary
Path traversal validation in widget file writes
app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java
Widget paths and derived JSON file paths are validated with validatePathIsWithinGitRoot before use during page/widget serialization in updateEntitiesInRepo.
Security tests for path traversal prevention
app/server/appsmith-git/src/test/java/com/appsmith/git/helpers/FileUtilsImplTest.java
Two new @Test cases verify that widget names containing traversal sequences throw RuntimeException and leave no files outside git root, while legitimate names serialize without error.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

Security, ok-to-test

Suggested reviewers

  • sondermanish

Poem

🛡️ Paths now stand guarded at the git root gate,
Widget names tested, no traversal escape,
Legitimate flows continue their fate,
Malicious attempts find no pathway or drape.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: adding path traversal validation to widget save paths for security fix GHSA-r553-q33m-v7pf.
Description check ✅ Passed The description comprehensively covers the vulnerability, root cause, attack scenario, fix implementation, testing approach, and CE/EE impact. It follows the template structure with clear issue links.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/widget-path-traversal-ghsa-r553-q33m-v7pf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/server/appsmith-git/src/test/java/com/appsmith/git/helpers/FileUtilsImplTest.java`:
- Around line 262-271: Ensure the test in FileUtilsImplTest cleans up the
traversal artifact and asserts the precise exception: before calling
fileUtils.saveApplicationToGitRepo(Path.of(""), appRef, "branch",
false).block(), delete the file at "/tmp/ghsa-r553-traversal-test.json" if it
exists so the assertion is not affected by prior state; replace
Assertions.assertThrows(RuntimeException.class, ...) with
Assertions.assertThrows(AppsmithPluginException.class, ...) so the test expects
the specific exception thrown by saveApplicationToGitRepo rather than any
RuntimeException.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 68639b5f-9ffd-4d09-a567-3368a024217f

📥 Commits

Reviewing files that changed from the base of the PR and between d44df5f and eff0ba7.

📒 Files selected for processing (2)
  • app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java
  • app/server/appsmith-git/src/test/java/com/appsmith/git/helpers/FileUtilsImplTest.java

Comment on lines +262 to +271
Assertions.assertThrows(RuntimeException.class, () -> {
fileUtils
.saveApplicationToGitRepo(Path.of(""), appRef, "branch", false)
.block();
});

Assertions.assertFalse(
Files.exists(Path.of("/tmp/ghsa-r553-traversal-test.json")),
"Path traversal: file was created outside git root");
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Pre-clean the traversal artifact and tighten the expected exception type.

Two small hygiene gaps in this regression test:

  1. Files.exists(Path.of("/tmp/ghsa-r553-traversal-test.json")) is not guarded against pre-existing state. If a prior run (with a regressed fix, or any unrelated process) left that file on disk, this assertion fails spuriously even when the current code is correct. Delete it before the action so the test is self-contained.
  2. assertThrows(RuntimeException.class, ...) is broader than necessary — the fix throws AppsmithPluginException. Asserting the specific type prevents an unrelated NullPointerException / RuntimeException from masquerading as a passing security test.
🛡️ Proposed tightening
+        Path traversalArtifact = Path.of("/tmp/ghsa-r553-traversal-test.json");
+        Files.deleteIfExists(traversalArtifact);
+
-        Assertions.assertThrows(RuntimeException.class, () -> {
+        Assertions.assertThrows(AppsmithPluginException.class, () -> {
             fileUtils
                     .saveApplicationToGitRepo(Path.of(""), appRef, "branch", false)
                     .block();
         });

         Assertions.assertFalse(
-                Files.exists(Path.of("/tmp/ghsa-r553-traversal-test.json")),
+                Files.exists(traversalArtifact),
                 "Path traversal: file was created outside git root");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/server/appsmith-git/src/test/java/com/appsmith/git/helpers/FileUtilsImplTest.java`
around lines 262 - 271, Ensure the test in FileUtilsImplTest cleans up the
traversal artifact and asserts the precise exception: before calling
fileUtils.saveApplicationToGitRepo(Path.of(""), appRef, "branch",
false).block(), delete the file at "/tmp/ghsa-r553-traversal-test.json" if it
exists so the assertion is not affected by prior state; replace
Assertions.assertThrows(RuntimeException.class, ...) with
Assertions.assertThrows(AppsmithPluginException.class, ...) so the test expects
the specific exception thrown by saveApplicationToGitRepo rather than any
RuntimeException.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses GHSA-r553-q33m-v7pf by adding path traversal validation to the widget file serialization path during Git repo saves, preventing user-controlled widgetName values from escaping the configured Git root during filesystem writes.

Changes:

  • Added validatePathIsWithinGitRoot(...) checks for both the widget directory path and the final widget JSON file path before writing widget files.
  • Added regression and positive tests covering malicious vs. legitimate widget names during saveApplicationToGitRepo serialization.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java Adds missing path traversal validation for widget serialization write paths.
app/server/appsmith-git/src/test/java/com/appsmith/git/helpers/FileUtilsImplTest.java Adds tests intended to validate traversal rejection and ensure normal widget serialization still works.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +268 to +270
Assertions.assertFalse(
Files.exists(Path.of("/tmp/ghsa-r553-traversal-test.json")),
"Path traversal: file was created outside git root");
Comment on lines +262 to +266
Assertions.assertThrows(RuntimeException.class, () -> {
fileUtils
.saveApplicationToGitRepo(Path.of(""), appRef, "branch", false)
.block();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Security Issues related to information security within the product

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants