Api Key Exposure in Grape with Mongodb
Api Key Exposure in Grape with Mongodb — how this specific combination creates or exposes the vulnerability
When a Grape API uses a MongoDB backend, developers sometimes embed sensitive credentials directly in route handlers or configuration files that are loaded by the application. If those files are committed to version control or logs are not properly sanitized, an API key can be inadvertently exposed. Grape routes often pass request parameters and headers into MongoDB queries, and if those values are used to construct queries without strict validation, an attacker may be able to influence the query in a way that reveals sensitive configuration or data.
Consider an endpoint that accepts a database name or collection name as a parameter to support multi-tenancy. If the application uses that parameter to select a MongoDB collection and then returns the result to the client, a malicious actor may attempt to traverse to a collection that contains connection strings or API keys. Even without direct injection, verbose error messages from the MongoDB driver can leak stack traces or internal paths that reference where the API key is stored or used.
Additionally, if the application serializes MongoDB documents directly into JSON responses, fields that should remain internal—such as api_key, secret, or internal identifiers—may be included unintentionally. In a Grape API, this often happens when developers use Model.all or similar methods and render the raw BSON documents as JSON. Without explicitly filtering sensitive keys, those values can be read by anyone who can call the endpoint, especially if rate limiting or authentication is misconfigured.
Another vector arises from log aggregation or debugging output. If the application logs full request and response payloads including MongoDB query results, an API key stored in a document could appear in logs and be accessible to unauthorized parties. MiddleBrick’s Data Exposure check specifically flags endpoints that return or log sensitive patterns resembling API keys, helping teams identify these risky integrations before exposure occurs in production.
Mongodb-Specific Remediation in Grape — concrete code fixes
To secure a Grape API that uses MongoDB, avoid exposing sensitive fields in responses and ensure queries are constructed safely. Always define explicit fields for serialization and filter out credentials before rendering JSON. Below is a secure Grape endpoint that retrieves user data from MongoDB while omitting sensitive keys.
# app/api/user.rb
require 'grape'
require 'mongo'
class UserAPI < Grape::API
format :json
helpers do
def mongo_client
@mongo_client ||= Mongo::Client.new(['127.0.0.1:27017'], database: 'myapp')
end
def safe_user_fields(user_doc)
# Explicitly select only safe fields, excluding api_key, secret, or internal flags
{
id: user_doc['_id'].to_s,
email: user_doc['email'],
name: user_doc['name']
}
end
end
resource :users do
params do
requires :user_id, type: String, desc: 'The user identifier'
end
get do
user_id = params[:user_id]
collection = mongo_client[:users]
user_doc = collection.find({ '_id' => BSON::ObjectId.from_string(user_id) }).first
unless user_doc
error!('User not found', 404)
end
safe_user_fields(user_doc)
end
end
end
In this example, the safe_user_fields helper ensures that only intended fields are returned, preventing accidental exposure of api_key or other sensitive attributes stored in the document. The query uses a parameterized _id lookup with BSON::ObjectId.from_string to avoid injection issues and relies on a controlled MongoDB client configuration.
For multi-tenant scenarios where the collection name is dynamic, validate the collection name against a strict allowlist instead of using raw user input. The following snippet demonstrates a safer approach:
# app/api/reports.rb
require 'grape'
require 'mongo'
class ReportAPI < Grape::API
format :json
ALLOWED_COLLECTIONS = %w[sales metrics events].freeze
helpers do
def mongo_client
@mongo_client ||= Mongo::Client.new(['127.0.0.1:27017'], database: 'analytics')
end
def safe_collection_name(name)
name if ALLOWED_COLLECTIONS.include?(name)
end
end
resource :reports do
params do
requires :collection, type: String, desc: 'The report collection name'
end
get do
collection_name = safe_collection_name(params[:collection])
unless collection_name
error!('Invalid collection', 400)
end
# Safe: collection_name is validated against an allowlist
docs = mongo_client[collection_name].find({}).limit(100).to_a
docs.map { |doc| doc.reject { |k| %w[password api_key token].include?(k) } }
end
end
end
Additionally, configure MongoDB connection strings using environment variables and never store them in source code. Use MongoDB’s built-in role-based access control to restrict what the application user can read and write, minimizing the impact if an API key is inadvertently exposed. MiddleBrick’s Authentication and BOLA checks can help verify that endpoints do not leak credentials and enforce proper authorization boundaries around sensitive data.