A recently discovered vulnerability in PostgreSQL, identified as CVE-2023-2455, has the potential to permit incorrect policies to be applied under specific conditions. The vulnerability affects databases that have row security policies defined using CREATE POLICY, and it can cause unintended consequences with inappropriate data access. In this post, we will discuss the impact of this vulnerability, mitigation methods, and how it can be exploited.

Vulnerability Details

A security flaw was discovered in PostgreSQL's implementation of row security policies, where these policies disregard user ID changes after inlining. The issue arises in cases where role-specific policies are used, and a query is planned under one role and then executed under other roles.

This scenario can happen under security definer functions or when a common user and query is planned initially and then re-used across multiple SET ROLEs. Applying an incorrect policy may permit a user to complete otherwise-forbidden reads and modifications.

Exploit Details

To exploit this vulnerability, an attacker needs to have access to a PostgreSQL database where row security policies have been defined using CREATE POLICY. Then, by carefully crafting queries under different roles, they can attempt to trick the system into applying incorrect policies, allowing them to access and modify data that they should not have permission to see or change.

Consider this example

-- Create a table with some rows
CREATE TABLE sensitive_data (username text, secret text);
INSERT INTO sensitive_data VALUES ('user1', 'password1');
INSERT INTO sensitive_data VALUES ('user2', 'password2');
INSERT INTO sensitive_data VALUES ('user3', 'password3');

-- Define row-level security policy
ALTER TABLE sensitive_data FORCE ROW LEVEL SECURITY;
CREATE POLICY user_access_policy
    ON sensitive_data
    FOR ALL
    USING (username = current_user);

-- Security definer function with an assumption that it should be executed by 'user1'
CREATE FUNCTION sensitive_data_of_user1()
    RETURNS SETOF sensitive_data
    LANGUAGE sql
    SECURITY DEFINER
    STABLE
AS $$
    SELECT * FROM sensitive_data;
$$;

-- Switch to the 'user2' role
SET ROLE user2;

-- Query the function - results should be empty as the function should return rows only for user1
SELECT * FROM sensitive_data_of_user1();

This code snippet demonstrates a possible scenario where, due to the vulnerability, user2 can improperly access sensitive_data_of_user1 results that were initially intended exclusively for user1.

Mitigation

While there is currently no security patch for this vulnerability, there are some recommended best practices to follow:

1. Regularly review and update row security policies to ensure their correctness and account for any changes in roles and user permissions.
2. Always create separate plans for separate roles, even if it is less efficient, to prevent policy leaks due to plan inlining.
3. Monitor PostgreSQL logs for changes to row security policies and unusual activity on sensitive tables.

References

- Official PostgreSQL Announcement: https://www.postgresql.org/about/news/vulnerability-cve-2023-2455-2384/
- PostgreSQL Documentation on Row Security Policies: https://www.postgresql.org/docs/current/ddl-rowsecurity.html
- NVD - CVE-2023-2455: https://nvd.nist.gov/vuln/detail/CVE-2023-2455

Conclusion

CVE-2023-2455 is a critical vulnerability in PostgreSQL that can lead to incorrect application of row security policies, potentially allowing unauthorized access to sensitive data. It is crucial to understand the implications of this vulnerability, review existing row security policies, and follow the recommended mitigation steps to protect your PostgreSQL installations.

Stay up-to-date with the latest PostgreSQL patches and subscribe to PostgreSQL's mailing list for any announcements related to security vulnerabilities and solutions.

Timeline

Published on: 06/09/2023 19:15:00 UTC
Last modified on: 06/16/2023 16:24:00 UTC