Auth Bypass in Postgresql
How Auth Bypass Manifests in Postgresql
Auth bypass in Postgresql typically occurs when authentication mechanisms are improperly implemented or when privilege escalation allows an attacker to bypass normal authentication flows. The most common Postgresql-specific auth bypass patterns include:
-- Vulnerable: Trust authentication method
host all all 0.0.0.0/0 trust
-- Vulnerable: MD5 with weak passwords
host all all 0.0.0.0/0 md5
-- Vulnerable: Peer authentication without proper user mapping
local all all peer
Trust authentication is particularly dangerous because it allows any connecting user to access the database without credentials. This is often found in development environments that get promoted to production without proper configuration changes.
Another Postgresql-specific auth bypass occurs through role privilege escalation. If a user has the CREATEROLE or CREATEDB privilege, they can create new roles or databases that inherit elevated permissions:
-- Attacker creates a new superuser role
CREATE ROLE attacker SUPERUSER LOGIN PASSWORD 'malicious';
-- Or creates a role with inherited privileges
CREATE ROLE attacker WITH INHERIT;
GRANT ALL PRIVILEGES ON DATABASE target TO attacker;
Function-based auth bypasses are also common in Postgresql. If a function is created with SECURITY DEFINER and an attacker can invoke it, they can execute code with the privileges of the function owner:
-- Vulnerable function definition
CREATE OR REPLACE FUNCTION vulnerable_func()
RETURNS void AS $$
BEGIN
-- Executes with owner privileges
EXECUTE 'DROP TABLE sensitive_data';
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- If attacker can call this function, they bypass authentication
SELECT vulnerable_func();
Postgresql's Row Level Security (RLS) misconfiguration can also lead to auth bypass. If RLS policies are not properly defined or are accidentally disabled, users can access rows they shouldn't see:
-- Vulnerable: RLS disabled
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Missing policies allow full access
-- No policy means all rows are accessible
Postgresql-Specific Detection
Detecting auth bypass vulnerabilities in Postgresql requires examining both configuration files and runtime behavior. The pg_hba.conf file is the primary location for authentication configuration:
# Check for trust authentication
grep -n "trust" /var/lib/postgresql/data/pg_hba.conf
# Check for weak authentication methods
grep -E "(md5|password)" /var/lib/postgresql/data/pg_hba.conf
# Check for overly permissive host access
grep -E "host.*all.*all.*0.0.0.0/0" /var/lib/postgresql/data/pg_hba.conf
Postgresql's system catalogs contain information about roles, privileges, and security configurations. Querying these can reveal potential auth bypass vectors:
-- Find superusers who can bypass authentication
SELECT rolname FROM pg_roles WHERE rolsuper = true;
-- Find roles with dangerous privileges
SELECT rolname, rolcreaterole, rolcreatedb, rolcanlogin
FROM pg_roles
WHERE rolcreaterole OR rolcreatedb OR rolcanlogin;
-- Check for functions with SECURITY DEFINER
SELECT n.nspname, p.proname, p.prosecdef
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE prosecdef = true;
middleBrick's Postgresql-specific scanning includes checking for these auth bypass patterns. The scanner examines pg_hba.conf configurations, queries system catalogs for privilege escalation opportunities, and tests for function-based bypasses:
# Scan a Postgresql API endpoint
middlebrick scan https://api.example.com/users
# The scanner will detect:
# - Trust authentication in pg_hba.conf
# - Superuser roles with excessive privileges
# - SECURITY DEFINER functions accessible to low-privilege users
# - Missing RLS policies
The scanner also tests for common Postgresql injection vectors that can lead to auth bypass, such as manipulating session variables or exploiting unquoted identifiers in dynamic SQL.
Postgresql-Specific Remediation
Remediating auth bypass vulnerabilities in Postgresql requires a defense-in-depth approach. Start with authentication configuration:
# Secure pg_hba.conf - replace trust with scram-sha-256
# Before:
host all all 0.0.0.0/0 trust
# After:
host all all 0.0.0.0/0 scram-sha-256
# Limit network access to specific subnets
host all all 192.168.1.0/24 scram-sha-256
Implement proper role management with the principle of least privilege:
-- Create application-specific role without dangerous privileges
CREATE ROLE app_user LOGIN PASSWORD 'strong_password' NOSUPERUSER NOCREATEROLE NOCREATEDB;
-- Grant only necessary privileges
GRANT SELECT, INSERT, UPDATE ON users TO app_user;
GRANT EXECUTE ON FUNCTION get_user_profile(INTEGER) TO app_user;
-- Revoke dangerous default privileges
REVOKE ALL ON DATABASE postgres FROM PUBLIC;
Secure function definitions by avoiding SECURITY DEFINER unless absolutely necessary:
-- Preferred: Explicit privilege checking
CREATE OR REPLACE FUNCTION get_user_profile(user_id INTEGER)
RETURNS users AS $$
DECLARE
result users%ROWTYPE;
BEGIN
-- Check current user's permissions
IF NOT has_row_access(CURRENT_USER, user_id) THEN
RAISE EXCEPTION 'Insufficient privileges';
END IF;
SELECT * INTO result FROM users WHERE id = user_id;
RETURN result;
END;
$$ LANGUAGE plpgsql;
-- If SECURITY DEFINER is required, limit scope
CREATE OR REPLACE FUNCTION admin_task()
SECURITY DEFINER
AS $$
BEGIN
-- Only allow execution from specific functions
IF current_function() != 'authorized_caller()' THEN
RAISE EXCEPTION 'Unauthorized access';
END IF;
-- Perform privileged operation
END;
$$ LANGUAGE plpgsql;
Implement Row Level Security to prevent unauthorized row access:
-- Enable RLS on sensitive tables
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Create policies that restrict access
CREATE POLICY user_policy ON users
FOR SELECT USING (id = current_setting('app.current_user_id')::INTEGER);
-- For update/delete operations, check ownership
CREATE POLICY update_policy ON users
FOR UPDATE USING (id = current_setting('app.current_user_id')::INTEGER);
-- Test RLS policies
SET app.current_user_id = '1';
SELECT * FROM users; -- Only returns rows owned by user 1
Finally, implement comprehensive logging and monitoring to detect auth bypass attempts:
-- Enable detailed logging
ALTER SYSTEM SET log_statement = 'all';
ALTER SYSTEM SET log_connections = on;
ALTER SYSTEM SET log_disconnections = on;
-- Create audit table for suspicious activity
CREATE TABLE auth_audit (
event_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
user_name TEXT,
operation TEXT,
object_name TEXT,
query TEXT
);
-- Create audit trigger
CREATE OR REPLACE FUNCTION audit_auth_bypass()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'EXECUTE' AND NEW.uses_superuser_privileges) THEN
INSERT INTO auth_audit (user_name, operation, object_name, query)
VALUES (CURRENT_USER, 'SUPERUSER_EXEC', TG_TABLE_NAME, current_query());
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |
Frequently Asked Questions
How does middleBrick detect Postgresql auth bypass vulnerabilities?
middleBrick scans Postgresql APIs by examining configuration files, querying system catalogs for privilege escalation opportunities, and testing for function-based bypasses. The scanner checks pg_hba.conf for trust authentication, identifies superuser roles, detects SECURITY DEFINER functions, and verifies RLS policies. It also tests for injection vectors that could lead to auth bypass. The scan takes 5-15 seconds and provides a security score with prioritized findings and remediation guidance.
What's the difference between trust authentication and scram-sha-256 in Postgresql?
Trust authentication allows any connecting user to access the database without credentials, making it extremely vulnerable to auth bypass. Scram-sha-256 is a strong authentication method that requires valid credentials and uses the SCRAM-SHA-256 protocol for secure password verification. Trust should never be used in production environments. middleBrick flags trust authentication as a critical finding and recommends switching to scram-sha-256 or certificate-based authentication for production systems.