HIGH dns cache poisoninghanami
Dns Cache Poisoning in Hanami
Hanami-Specific Remediation
The fix is to ensure that any hostname used in an outbound request is validated against a known‑good list, or that the application performs its own DNS resolution with security‑hardened options and does not rely solely on the system resolver’s potentially poisoned cache.
Below is a Hanami‑style solution using an allowlist and Ruby’s Resolv::DNS with a short timeout and the use_tcp flag to reduce susceptibility to UDP‑based cache poisoning.
# lib/web/extensions/safe_http.rb
module Web::Extensions
module SafeHttp
ALLOWED_HOSTS = %w[api.example.com images.cdn.com].freeze
def safe_get(uri_string)
uri = URI.parse(uri_string)
raise "Invalid URI" unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
# 1. Host allowlist
unless ALLOWED_HOSTS.include?(uri.host)
raise "Host not allowed: #{uri.host}"
end
# 2. Perform DNS query with hardened resolver
resolver = Resolv::DNS.new(nameserver: ["8.8.8.8"], udp_timeout: 2)
resolver.timeout = 2
# Force TCP for the query (harder to poison)
addresses = resolver.getresources(uri.host, Resolv::DNS::Resource::IN::A)
if addresses.empty?
raise "Unable to resolve host"
end
# 3. Use the first resolved IP for the connection (bypasses system cache)
ip = addresses.first.address
http_uri = URI::HTTP.build(host: ip, port: uri.port, path: uri.path, query: uri.query)
Net::HTTP.start(http_uri.host, http_uri.port, use_ssl: uri.is_a?(URI::HTTPS)) do |http|
request = Net::HTTP::Get.new(http_uri.request_uri)
response = http.request(request)
response.body
end
end
end
end
Now refactor the vulnerable action to use the extension:
# apps/web/actions/images/proxy.rb
module Web::Actions::Images
class Proxy < Web::Action
include Web::Extensions::SafeHttp
def handle(params, response)
target = params[:url] || ""
begin
response.body = safe_get(target)
response.status = 200
rescue => e
response.status = 400
response.body = { error: e.message }.to_json
end
end
end
end
Additional mitigations that fit naturally into a Hanami project:
- Configure Hanami’s
config.security.allowed_outbound_hosts(custom setting) and read it in a middleware or action. - Use
Hanami::Utils::URIto safely parse and reconstruct URIs, avoiding injection of malformed components. - Set short open and read timeouts on
Net::HTTP(read_timeout = 2) to limit the window for a poisoned response to cause damage. - If you rely on external gems (e.g.,
faradayorhttparty), wrap them with the same allowlist/resolver logic.
After applying these changes, a middleBrick scan will no longer report an SSRF finding for the proxy endpoint, confirming that the DNS cache poisoning vector has been mitigated.
Frequently Asked Questions
Can middleBrick detect DNS cache poisoning that only affects internal DNS resolvers and not the public internet?
middleBrick performs unauthenticated, black‑box checks from the public internet. If an organization’s internal resolver is poisoned but external resolvers return correct records, the scanner will not see the malicious resolution. To catch such scenarios, run middleBrick against an internal staging endpoint or integrate the scanner into a private CI environment where the same DNS infrastructure is used.
Does fixing DNS cache poisoning in Hanami require changes to the application’s OpenAPI/Swagger spec?
No. The remediation lives in the Ruby code (allowlist validation and hardened DNS lookup). middleBrick will still parse the OpenAPI spec to correlate findings with specific operations, but the spec itself does not need to be updated unless you want to document the new security constraints (e.g., adding a
x‑allowed‑hosts extension).