Skip to content

fix: the post /reset endpoint in the real-time servi... in git_routes.ts#41898

Open
orbisai0security wants to merge 4 commits into
appsmithorg:releasefrom
orbisai0security:fix-v-002-git-reset-request-validation
Open

fix: the post /reset endpoint in the real-time servi... in git_routes.ts#41898
orbisai0security wants to merge 4 commits into
appsmithorg:releasefrom
orbisai0security:fix-v-002-git-reset-request-validation

Conversation

@orbisai0security

@orbisai0security orbisai0security commented Jun 13, 2026

Copy link
Copy Markdown

Summary

Fix high severity security issue in app/client/packages/rts/src/routes/git_routes.ts.

Vulnerability

Field Value
ID V-002
Severity HIGH
Scanner multi_agent_ai
Rule V-002
File app/client/packages/rts/src/routes/git_routes.ts:9
Assessment Confirmed exploitable
Chain Complexity 2-step

Description: The POST /reset endpoint in the Real-Time Service (RTS) Git routes uses only a generic request validator without explicit authentication or authorization middleware. This state-changing endpoint could allow unauthorized users to reset Git repositories associated with Appsmith applications, potentially destroying version history or reverting applications to previous states.

Evidence

Exploitation scenario: An attacker with network access to the RTS service sends a crafted POST request to /reset with a valid request structure.

Scanner confirmation: multi_agent_ai rule V-002 flagged this pattern.

Production code: This file is in the production codebase, not test-only code.

Threat Model Context

This route handler appears to be publicly accessible. This is a containerized service - vulnerabilities may be exploitable depending on network exposure.

Changes

  • app/client/packages/rts/src/routes/git_routes.ts

Verification

  • Build passes
  • Scanner re-scan confirms fix
  • LLM code review passed

Security Invariant

Property: Protected endpoints reject unauthenticated requests

Regression test
import request from 'supertest';
import express from 'express';
import gitRoutes from '../../../src/routes/git_routes';

describe('Protected endpoints reject unauthenticated requests', () => {
  let app: express.Application;

  beforeAll(() => {
    app = express();
    app.use(express.json());
    app.use('/git', gitRoutes);
  });

  const payloads = [
    { name: 'missing_auth_header', headers: {}, expectedStatus: 401 },
    { name: 'invalid_token', headers: { authorization: 'Bearer invalid_token_xyz' }, expectedStatus: 401 },
    { name: 'expired_token', headers: { authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDAwMDAwMDB9.invalid' }, expectedStatus: 401 },
    { name: 'malformed_auth', headers: { authorization: 'InvalidScheme token123' }, expectedStatus: 401 },
    { name: 'empty_token', headers: { authorization: 'Bearer ' }, expectedStatus: 401 },
  ];

  test.each(payloads)(
    'POST /reset rejects unauthenticated request: $name',
    async ({ headers, expectedStatus }) => {
      const response = await request(app)
        .post('/git/reset')
        .set(headers)
        .send({ repositoryId: 'test-repo' });

      expect([401, 403]).toContain(response.status);
    }
  );
});

This test guards against regressions — it's useful independent of the code change above.


Automated security fix by OrbisAI Security

Summary by CodeRabbit

  • Bug Fixes
    • Secured POST /git/reset so it now requires internal authentication via the x-rts-secret header.
    • Added request validation for repoPath, ensuring it is present and a non-empty string with improved error messaging.
  • Tests
    • Added integration coverage to verify POST /git/reset returns 401 Unauthorized for unauthenticated and invalid x-rts-secret scenarios (missing, malformed, empty, or invalid).

Automated security fix generated by OrbisAI Security
The POST /reset endpoint in the Real-Time Service (RTS) Git routes uses only a generic request validator without explicit authentication or authorization middleware
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The /reset endpoint now requires internal header-based authentication, validates repoPath as a required non-empty string, and has integration coverage for unauthorized requests.

Changes

Git Reset Endpoint Security

Layer / File(s) Summary
Internal authentication middleware
app/client/packages/rts/src/middlewares/AuthMiddleware.ts
New requireInternalAuth middleware checks APPSMITH_RTS_SECRET against the x-rts-secret header and returns HTTP 401 JSON when the secret is unset or the header is missing or mismatched.
Route security with validation
app/client/packages/rts/src/routes/git_routes.ts
POST /reset now chains body("repoPath") validation, requireInternalAuth, request validation, and gitController.reset.
Authentication rejection tests
tests/invariant_git_routes.test.ts
A new integration suite asserts POST /git/reset returns HTTP 401 for unauthenticated requests across multiple header scenarios.

Sequence Diagram

sequenceDiagram
  participant Client
  participant GitRoutes as gitRoutes
  participant AuthMiddleware as requireInternalAuth
  participant ValidateRequest as validator.validateRequest
  participant GitController as gitController.reset

  Client->>GitRoutes: POST /reset {repoPath}
  GitRoutes->>GitRoutes: body("repoPath") validation
  GitRoutes->>AuthMiddleware: requireInternalAuth
  alt x-rts-secret missing or mismatched
    AuthMiddleware->>Client: 401 JSON
  else secret matches
    AuthMiddleware->>ValidateRequest: next()
    ValidateRequest->>GitController: next()
    GitController->>Client: reset response
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🔐 A secret guard at reset stands,
Checking headers and requester's hands.
A repo path must be neat and true,
Then tests confirm the 401 view.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 matches the main change by calling out the POST /reset endpoint fix in git_routes.ts, though it is slightly truncated.
Description check ✅ Passed It includes the key security context, verification, and regression test details; only template extras like the issue link, automation, and comms are missing.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 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/client/packages/rts/src/routes/git_routes.ts`:
- Around line 10-15: The POST /reset route currently only validates the body
then calls gitController.reset; add the RTS authentication/authorization
middleware into the router.post call so it runs before validator.validateRequest
and before gitController.reset (i.e., change the middleware chain for
router.post("/reset", body(...), <auth middleware>, validator.validateRequest,
gitController.reset) so unauthorized callers cannot invoke gitController.reset).

In `@tests/invariant_git_routes.test.ts`:
- Around line 24-31: The test block calling request(app).post('/git/reset') is
sending an invalid body key (repositoryId) so validation can fail before auth;
change the payload to send the required repoPath (e.g., .send({ repoPath:
'test-repo' })) and replace the loose expect([401,
403]).toContain(response.status) with a strict assertion against the
table-driven value (e.g., expect(response.status).toBe(expectedStatus)) so each
case verifies the intended auth rejection; update the variables used in this
test (headers, expectedStatus) accordingly.
🪄 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: 3f415e70-a2fc-4ad5-ad93-f9740089daab

📥 Commits

Reviewing files that changed from the base of the PR and between 057cc61 and 07ef29e.

📒 Files selected for processing (2)
  • app/client/packages/rts/src/routes/git_routes.ts
  • tests/invariant_git_routes.test.ts

Comment thread app/client/packages/rts/src/routes/git_routes.ts
Comment thread tests/invariant_git_routes.test.ts
@github-actions

Copy link
Copy Markdown

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions Bot added the Stale label Jun 20, 2026
- Add requireInternalAuth middleware (APPSMITH_RTS_SECRET header check)
  so unauthorized callers cannot reach gitController.reset
- Fix test to send correct body field (repoPath), set env var so auth
  is enforced during test, and assert strict status code per table row

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 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/client/packages/rts/src/middlewares/AuthMiddleware.ts`:
- Around line 5-7: The AuthMiddleware.ts file currently silently bypasses
authentication when the secret is undefined by calling next(), which leaves the
endpoint unprotected if APPSMITH_RTS_SECRET is misconfigured. Replace the silent
bypass in the check for !secret with a fail-closed approach that returns a 401
or 503 status code, or at minimum log a warning to alert operators that
authentication is disabled. This ensures the security fix is not inadvertently
circumvented due to missing environment configuration.

In `@tests/invariant_git_routes.test.ts`:
- Around line 8-17: The beforeAll and afterAll hooks mutate the global
process.env without preserving pre-existing values, causing test pollution. In
the beforeAll block, before setting process.env.APPSMITH_RTS_SECRET to
'test-secret', store the original value of process.env.APPSMITH_RTS_SECRET in a
variable. In the afterAll block, instead of deleting the environment variable,
restore it to the original value that was saved (this ensures that if the
variable existed before the test, it is properly restored to its original state,
or if it didn't exist, it remains undefined).
🪄 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: 35b25677-aa8e-47e5-9a30-883fdb1927b7

📥 Commits

Reviewing files that changed from the base of the PR and between 07ef29e and 254ee2f.

📒 Files selected for processing (3)
  • app/client/packages/rts/src/middlewares/AuthMiddleware.ts
  • app/client/packages/rts/src/routes/git_routes.ts
  • tests/invariant_git_routes.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/client/packages/rts/src/routes/git_routes.ts

Comment thread app/client/packages/rts/src/middlewares/AuthMiddleware.ts
Comment thread tests/invariant_git_routes.test.ts
@github-actions github-actions Bot removed the Stale label Jun 21, 2026
@github-actions

Copy link
Copy Markdown

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions Bot added the Stale label Jun 29, 2026
…1898

- Make requireInternalAuth fail-closed when APPSMITH_RTS_SECRET is unset
  (previously silently bypassed auth; now returns 401 + console.warn)
- Preserve and restore original env var value in test beforeAll/afterAll
  to avoid test pollution when the variable is already set in the environment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/client/packages/rts/src/middlewares/AuthMiddleware.ts (1)

6-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fail-closed behavior looks correct; swap console.warn for the structured logger.

The 401 + warning on missing APPSMITH_RTS_SECRET correctly closes the silent-bypass gap from the prior review. One nit: console.warn for a security-relevant misconfiguration won't reach Sentry/OpenTelemetry, so operators may never see it. Route it through the RTS logger so it surfaces in observability.

🔭 Suggested change to use structured logging
+import log from "loglevel";
+
 export function requireInternalAuth(req: Request, res: Response, next: NextFunction) {
   const secret = process.env.APPSMITH_RTS_SECRET;
   if (!secret) {
-    console.warn("[AuthMiddleware] APPSMITH_RTS_SECRET is not set; rejecting request to protected endpoint");
+    log.warn("[AuthMiddleware] APPSMITH_RTS_SECRET is not set; rejecting request to protected endpoint");
     return res.status(401).json({ success: false, message: "Unauthorized" });
   }

As per coding guidelines: "RTS must implement OpenTelemetry and Sentry instrumentation for observability".

🤖 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/client/packages/rts/src/middlewares/AuthMiddleware.ts` around lines 6 -
7, Replace the direct console.warn in AuthMiddleware with the RTS structured
logger so the missing APPSMITH_RTS_SECRET warning is captured by observability
tooling. Locate the protected-endpoint check in AuthMiddleware and route that
security misconfiguration message through the existing logger used elsewhere in
the RTS package, preserving the same 401 fail-closed response while ensuring it
can surface in Sentry/OpenTelemetry.

Source: Coding guidelines

🤖 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 `@tests/invariant_git_routes.test.ts`:
- Around line 9-15: The current invariant_git_routes.test.ts setup in beforeAll
always sets APPSMITH_RTS_SECRET, so it never covers the new fail-closed
behavior. Add a regression test around gitRoutes that temporarily removes
APPSMITH_RTS_SECRET before issuing the request and asserts the route returns
401, then restore the original env value so other cases still run with the test
secret. Use the existing app setup and route names to locate the test logic.

---

Nitpick comments:
In `@app/client/packages/rts/src/middlewares/AuthMiddleware.ts`:
- Around line 6-7: Replace the direct console.warn in AuthMiddleware with the
RTS structured logger so the missing APPSMITH_RTS_SECRET warning is captured by
observability tooling. Locate the protected-endpoint check in AuthMiddleware and
route that security misconfiguration message through the existing logger used
elsewhere in the RTS package, preserving the same 401 fail-closed response while
ensuring it can surface in Sentry/OpenTelemetry.
🪄 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: 139864d6-fcbf-4d5d-8c3e-3ef452e46c7c

📥 Commits

Reviewing files that changed from the base of the PR and between 254ee2f and fd6f47b.

📒 Files selected for processing (2)
  • app/client/packages/rts/src/middlewares/AuthMiddleware.ts
  • tests/invariant_git_routes.test.ts

Comment on lines +9 to +15
beforeAll(() => {
originalSecret = process.env.APPSMITH_RTS_SECRET;
process.env.APPSMITH_RTS_SECRET = 'test-secret';
app = express();
app.use(express.json());
app.use('/git', gitRoutes);
});

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.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Add a regression case for an unset APPSMITH_RTS_SECRET.

Line 11 forces the secret for every case, so this suite never exercises the new fail-closed branch that should return 401 when the env var is missing. Please add one case that removes the env var before the request and asserts the rejection path too.

🧰 Tools
🪛 ast-grep (0.44.0)

[warning] 11-11: Express application should use Helmet
Context: express()
Note: [CWE-693] Protection Mechanism Failure (Express app without Helmet security headers).

(missing-helmet-typescript)

🤖 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 `@tests/invariant_git_routes.test.ts` around lines 9 - 15, The current
invariant_git_routes.test.ts setup in beforeAll always sets APPSMITH_RTS_SECRET,
so it never covers the new fail-closed behavior. Add a regression test around
gitRoutes that temporarily removes APPSMITH_RTS_SECRET before issuing the
request and asserts the route returns 401, then restore the original env value
so other cases still run with the test secret. Use the existing app setup and
route names to locate the test logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants