HIGH api key exposurehanamipostgresql

Api Key Exposure in Hanami with Postgresql

Api Key Exposure in Hanami with Postgresql — how this specific combination creates or exposes the vulnerability

Hanami is a Ruby web framework that encourages explicit architecture and strict separation of concerns. When Hanami applications interact with Postgresql, developers often store database credentials, external service tokens, or encryption keys in environment variables or initializer files. If those keys are inadvertently logged, serialized, or exposed through an API endpoint, the combination of Hanami’s object-oriented structure and Postgresql’s role-based access control can amplify the impact of a leak.

For example, a Hanami app might define a repository class that reads DATABASE_URL or a custom API_KEY from ENV. If an attacker gains read access to application logs, error messages, or backup artifacts stored in Postgresql tables (for instance, a mistakenly created debug_log table), they can retrieve these keys. Postgresql’s row-level security may not be enforced for certain read paths, especially during development, allowing an unauthorized database user or compromised application process to dump sensitive columns.

Another common scenario involves connection strings embedded in Hanami’s config/environment.rb or via hanami config commands. If these configurations are accidentally serialized into JSON or YAML responses—such as an unguarded admin endpoint that returns system diagnostics—Postgresql can act as a storage layer for those artifacts if backups or audit tables capture them. Because Hanami encourages immutable, value objects, developers may mistakenly assume that storing configuration in plain Ruby constants is safe, but those constants can appear in memory dumps or log entries that ultimately persist in Postgresql-based logging schemas.

The risk is further compounded when Hanami applications use Postgresql’s LISTEN/NOTIFY features for real-time updates. If a notification payload includes an API key or a token, and that channel is not properly restricted, an unauthenticated subscriber could intercept sensitive data. Additionally, ORM layers built on top of Postgresql, such as those using sequel or active_record adapters, might expose keys through misconfigured query logs or through error messages that reveal SQL statements containing literal values.

To detect such exposures with middleBrick, you can submit your Hanami service endpoint for a scan. The tool runs unauthenticated checks across multiple security domains, including Data Exposure and Unsafe Consumption, to identify whether API keys appear in responses, logs, or error payloads. Because middleBrick maps findings to frameworks like OWASP API Top 10 and provides remediation guidance, it helps you understand how a leaked key in a Hanami + Postgresql context could lead to privilege escalation or data exfiltration.

Postgresql-Specific Remediation in Hanami — concrete code fixes

Securing API keys in a Hanami application that uses Postgresql requires changes at the configuration, runtime, and database layers. Below are concrete, actionable steps with valid Postgresql code examples tailored for Hanami.

1. Use environment variables and avoid hardcoding

Never embed API keys directly in Hanami initializers. Instead, rely on environment variables and validate their presence at boot.

# config/environment.rb
require "hanami/config/environment"

module MyApp
  class Environment < Hanami::Environment
    def initialize
      super
      # Ensure required keys are present
      raise "ENV['DATABASE_URL'] missing" if ENV["DATABASE_URL"].to_s.empty?
      raise "ENV['API_KEY'] missing" if ENV["API_KEY"].to_s.empty?
    end
  end
end

2. Configure Postgresql connections securely

Use connection strings that reference environment variables and avoid storing credentials in code. Apply the principle of least privilege to the Postgresql role used by Hanami.

# config/database.yml (if using YAML-style setup with a DSN)
development:
  url: postgresql://<%= ENV["DB_USER"] %>:<%= ENV["DB_PASS"] %>@localhost:5432/<%= ENV["DB_NAME"] %>

# Or via direct URL
# DATABASE_URL=postgresql://lowpriv_user:[email protected]:5432/hanami_prod

In Postgresql, create a restricted role for Hanami:

-- Execute in psql
CREATE ROLE hanami_app WITH LOGIN PASSWORD 'strong_password' NOINHERIT;
GRANT CONNECT ON DATABASE hanami_production TO hanami_app;
GRANT USAGE ON SCHEMA public TO hanami_app;
GRANT SELECT, INSERT, UPDATE ON TABLE users, sessions TO hanami_app;
-- Explicitly deny dangerous privileges
REVOKE CREATE ON DATABASE hanami_production FROM hanami_app;
REVOKE ALL ON SCHEMA public FROM PUBLIC;

3. Avoid logging sensitive values

Ensure that Hanami’s logger and any custom debug tables do not capture API keys or connection strings. If you must store logs in Postgresql, sanitize sensitive fields.

# lib/hanami/logging_filter.rb
module Hanami
  module LoggingFilter
    FILTER_KEYS = ["api_key", "authorization", "password", "token"].freeze

    def call(request)
      filtered_params = request.params.map do |key, value|
        [key, FILTER_KEYS.include?(key) ? "[FILTERED]" : value]
      end.to_h
      super(request.dup.update_params(filtered_params))
    end
  end
end

Create a Postgresql audit table with masked columns:

CREATE TABLE api_logs (
  id SERIAL PRIMARY KEY,
  endpoint TEXT NOT NULL,
  method TEXT NOT NULL,
  masked_params JSONB,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Function to sanitize before insert
CREATE OR REPLACE FUNCTION log_sanitized_params(params JSONB)
RETURNS JSONB AS $$
DECLARE
  sanitized JSONB := params;
  key TEXT;
BEGIN
  FOREACH key IN ARRAY ARRAY['api_key','token','password']
  LOOP
    sanitized := jsonb_set(sanitized, ARRAY[key], '"[FILTERED]"'::jsonb, true);
  END LOOP;
  RETURN sanitized;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

4. Secure handling of notifications and external calls

If your Hanami app uses Postgresql LISTEN/NOTIFY, avoid placing secrets in payloads. If you must transmit sensitive references, use opaque identifiers and resolve them server-side.

# Sending a notification without secrets
NOTIFY channel_name, '{"event":"refresh","record_id":"123"}';

-- Receiver side in Hanami (pseudo-code)
Hanami::Notifications.subscribe("channel_name") do |payload|
  data = JSON.parse(payload)
  # Fetch sensitive data using a secure service, not from payload
end

5. Continuous validation with middleBrick

Use the middleBrick CLI to regularly scan your Hanami endpoints for exposed keys. The tool checks Data Exposure and Unsafe Consumption checks, and with the Pro plan you can enable continuous monitoring to catch regressions early.

$ middlebrick scan https://api.yourapp.com/health

Frequently Asked Questions

How can I verify that my Postgresql role for Hanami has the minimum required privileges?
Connect via psql and run \dp to inspect table privileges, and SELECT rolname, rolsuper, rolinherit FROM pg_roles WHERE rolname='hanami_app';. Ensure no CREATE or DROP rights are granted.
Does middleBrick remove or fix exposed API keys found in Hanami logs stored in Postgresql?
No. middleBrick detects and reports exposures with remediation guidance; it does not modify logs, databases, or application state.