ruby 20 lines · 1 tab

SSRF mitigation with URL allowlists and egress controls

Kai Nakamura Apr 2026
1 tab
require 'ipaddr'
require 'resolv'

uri = URI.parse(params[:url])
allowed_hosts = %w[images.example-cdn.com api.partner.com]

raise ActionController::BadRequest, 'invalid scheme' unless %w[https].include?(uri.scheme)
raise ActionController::BadRequest, 'host not allowed' unless allowed_hosts.include?(uri.host)

addresses = Resolv.getaddresses(uri.host).map { |address| IPAddr.new(address) }
forbidden_ranges = [
  IPAddr.new('127.0.0.0/8'),
  IPAddr.new('10.0.0.0/8'),
  IPAddr.new('172.16.0.0/12'),
  IPAddr.new('192.168.0.0/16'),
]

if addresses.any? { |address| forbidden_ranges.any? { |range| range.include?(address) } }
  raise ActionController::BadRequest, 'resolved to forbidden network'
end
1 file · ruby Explain with highlit

SSRF defense requires more than banning localhost. I parse URLs with a real library, enforce scheme and host allowlists, resolve and reject private IP ranges, and pair app-level checks with network egress rules. If an attacker can turn your server into a proxy, they will eventually find something sensitive behind it.


Related snips

ruby
# Vulnerable: user input is concatenated directly into SQL.
email = params[:email]
password = params[:password]

sql = "SELECT * FROM users WHERE email = '#{email}' AND password_hash = '#{password}'"
user = ActiveRecord::Base.connection.execute(sql).first

SQL injection prevention with unsafe and safe query patterns

sql-injection owasp database
by Kai Nakamura 3 tabs
ruby
RegistrationSchema = Dry::Schema.Params do
  required(:email).filled(:string, format?: URI::MailTo::EMAIL_REGEXP)
  required(:password).filled(:string, min_size?: 12)
  optional(:marketing_opt_in).filled(:bool)
  optional(:country).filled(:string, included_in?: %w[US CA GB AU])
end

Input validation with allowlists and explicit schemas

input-validation schemas secure-coding
by Kai Nakamura 1 tab
ruby
raw_token = SecureRandom.urlsafe_base64(32)
token_digest = Digest::SHA256.hexdigest(raw_token)

PasswordReset.create!(
  user: user,
  token_digest: token_digest,

Secure random token generation for sessions and recovery flows

randomness tokens authentication
by Kai Nakamura 1 tab
python
import psycopg

with psycopg.connect(conninfo) as connection:
    with connection.cursor() as cursor:
        cursor.execute(
            'SELECT id, email FROM users WHERE email = %s',

Parameterized queries in Python with psycopg

python sql-injection psycopg
by Kai Nakamura 1 tab
python
from defusedxml.ElementTree import fromstring

payload = request.data.decode('utf-8')
root = fromstring(payload)
invoice_number = root.findtext('invoice_number')

XXE safe XML parsing with external entity resolution disabled

xxe xml parsing
by Kai Nakamura 1 tab
plaintext
local   all             postgres                                peer
hostssl app_production  app_user        10.0.0.0/16             scram-sha-256
hostssl app_production  reporting_user  10.0.1.0/24             scram-sha-256
host    all             all             0.0.0.0/0               reject

PostgreSQL hardening with pg_hba and strict role separation

postgresql database-hardening roles
by Kai Nakamura 1 tab

Share this code

Here's the card — post it anywhere.

SSRF mitigation with URL allowlists and egress controls — share card
Link copied