Pii Leakage in Grape
How PII Leakage Manifests in Grape
PII leakage in Grape APIs typically occurs through several Grape-specific patterns. The most common is improper serialization of ActiveRecord objects in API responses. When developers use Grape's present method without explicitly specifying attributes, all model attributes—including sensitive ones like email, phone_number, or ssn—are exposed by default.
# Vulnerable Grape endpoint
class UsersAPI < Grape::API
format :json
desc 'Get user details'
get '/users/:id' do
user = User.find(params[:id])
present user, with: Entities::User
end
end
# Entity exposing all attributes
class Entities::User < Grape::Entity
expose :all
end
This code would leak all user attributes, including PII, because expose :all serializes every column from the database table. Another common Grape-specific vulnerability occurs with dynamic response building using present without entity classes:
# Vulnerable dynamic response
get '/users/:id' do
user = User.find(params[:id])
present user, with: { email: user.email, phone: user.phone_number }
end
While this seems safe, if the response object structure changes or if additional attributes are added to the user object, PII can inadvertently be exposed. Grape's flexible parameter handling also creates PII leakage risks when sensitive data is accepted in request bodies but not properly filtered before database operations:
# Vulnerable parameter handling
params do
requires :email, type: String
requires :password, type: String
requires :ssn, type: String
end
Here, the SSN parameter is accepted but might be stored or logged without proper controls. Additionally, Grape's error handling can leak PII through detailed error messages that include stack traces or parameter dumps containing sensitive information.
Grape-Specific Detection
Detecting PII leakage in Grape APIs requires examining both the API structure and runtime behavior. Start by analyzing your Grape endpoint definitions for entity exposure patterns. Use Grape's built-in introspection to identify all exposed attributes:
# Scan for exposed attributes
class PIIScanner < Grape::API
get '/pii_scan' do
exposed_attrs = []
self.class.endpoints.each do |endpoint|
endpoint.options[:for].class.ancestors.each do |klass|
next unless klass < Grape::Entity
klass.exposures.each do |attr, config|
exposed_attrs << { endpoint: endpoint.path, attribute: attr, source: config[:from] }
end
end
end
exposed_attrs
end
end
For runtime detection, middleBrick's black-box scanning can identify PII exposure by analyzing API responses against known PII patterns. The scanner tests endpoints with synthetic data and uses regex patterns to detect PII in responses:
# Scan with middleBrick CLI
middlebrick scan https://api.example.com/users/123 --category pii
The scan tests for common PII patterns including email addresses, phone numbers, SSNs, credit card numbers, and addresses. middleBrick's LLM security module specifically checks for system prompt leakage and excessive agency patterns that could expose PII through AI-powered endpoints. For comprehensive coverage, combine static analysis of your Grape codebase with dynamic scanning:
# Static analysis script
require 'find'
pii_patterns = [/email/, /phone/, /ssn/, /credit_card/, /address/]
Find.find('app/api') do |path|
next unless path.end_with?('.rb')
File.open(path) do |file|
file.each_line.with_index do |line, line_num|
if line.include?('expose') && pii_patterns.any? { |pattern| line.match?(pattern) }
puts "PII exposure found: #{path}:#{line_num + 1}"
puts line
end
end
end
end
This script identifies potential PII exposure by scanning Grape entity files for sensitive attribute names in expose statements.
Grape-Specific Remediation
Remediating PII leakage in Grape requires a multi-layered approach using Grape's built-in features. First, implement strict entity definitions that explicitly control attribute exposure:
# Secure entity definition
class Entities::User < Grape::Entity
expose :id
expose :username
expose :created_at
# Exclude sensitive attributes
# expose :email # Remove this line
# expose :phone_number # Remove this line
# expose :ssn # Remove this line
end
Always use explicit entity classes rather than dynamic present calls. For attributes that need conditional exposure, use Grape's conditional exposure feature:
class Entities::User < Grape::Entity
expose :id
expose :username
expose :email, if: { auth_level: :admin }
expose :phone_number, if: { auth_level: :admin }
end
Implement parameter filtering to prevent sensitive data from being accepted in requests:
# Filter sensitive parameters
params do
requires :username, type: String
optional :email, type: String
# Remove sensitive parameters
# requires :ssn, type: String
# requires :credit_card, type: String
end
Use Grape's before_validation hooks to sanitize incoming data:
# Sanitize sensitive data
before_validation do
# Remove sensitive parameters from params
%i[ssn credit_card ssn_last_four].each { |key| params.delete(key) }
# Mask PII in logs
Rails.logger.info("User login: #{params[:username]}") if params[:username]
end
For error handling, implement custom error formats that don't expose sensitive data:
# Custom error format
class ErrorFormatter < Grape::Formatter::Base
def self.call(object, env)
# Remove sensitive data from error responses
error_data = object.is_a?(Hash) ? object.except(:password, :ssn, :credit_card) : object
{ error: error_data, status: 400 }.to_json
end
end
# Use custom formatter
format :json, ErrorFormatter
Implement logging controls to prevent PII from being written to logs:
# Secure logging
before do
# Mask sensitive parameters
request.env['action_dispatch.request.parameters'].tap do |params|
params['email'] = '***' if params['email']
params['phone'] = '***' if params['phone']
end
end
Finally, use middleBrick's continuous monitoring to ensure your remediations remain effective over time. The Pro plan's scheduled scanning will alert you if new PII exposure is introduced through code changes.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |