Constrain Lunchflow base URL to trusted endpoint (#1768)

* Constrain Lunchflow base URL to trusted endpoint

Prevent SSRF by ignoring user-provided Lunchflow base_url values unless they match the canonical Lunchflow HTTPS endpoint. Add model tests covering invalid host/scheme and valid canonicalization behavior.

* Linter
This commit is contained in:
Juan José Mata
2026-05-12 12:18:17 +02:00
committed by GitHub
parent 5ceb55be03
commit 73b6077ac3
2 changed files with 45 additions and 1 deletions

View File

@@ -1,6 +1,8 @@
class LunchflowItem < ApplicationRecord
include Syncable, Provided, Unlinking, Encryptable
DEFAULT_BASE_URL = "https://lunchflow.app/api/v1".freeze
enum :status, { good: "good", requires_update: "requires_update" }, default: :good
# Encrypt sensitive credentials and raw payloads if ActiveRecord encryption is configured
@@ -154,6 +156,17 @@ class LunchflowItem < ApplicationRecord
end
def effective_base_url
base_url.presence || "https://lunchflow.app/api/v1"
return DEFAULT_BASE_URL if base_url.blank?
uri = URI.parse(base_url)
return DEFAULT_BASE_URL unless uri.is_a?(URI::HTTPS)
return DEFAULT_BASE_URL unless uri.host == "lunchflow.app"
return DEFAULT_BASE_URL unless [ "", "/", "/api/v1", "/api/v1/" ].include?(uri.path)
return DEFAULT_BASE_URL unless uri.query.blank?
return DEFAULT_BASE_URL unless uri.fragment.blank?
DEFAULT_BASE_URL
rescue URI::InvalidURIError
DEFAULT_BASE_URL
end
end

View File

@@ -0,0 +1,31 @@
require "test_helper"
class LunchflowItemTest < ActiveSupport::TestCase
def setup
@lunchflow_item = lunchflow_items(:one)
end
test "effective_base_url returns default when base_url blank" do
@lunchflow_item.base_url = nil
assert_equal LunchflowItem::DEFAULT_BASE_URL, @lunchflow_item.effective_base_url
end
test "effective_base_url returns default for non-lunchflow host" do
@lunchflow_item.base_url = "https://169.254.169.254/latest/meta-data"
assert_equal LunchflowItem::DEFAULT_BASE_URL, @lunchflow_item.effective_base_url
end
test "effective_base_url returns default for non-https scheme" do
@lunchflow_item.base_url = "http://lunchflow.app/api/v1"
assert_equal LunchflowItem::DEFAULT_BASE_URL, @lunchflow_item.effective_base_url
end
test "effective_base_url returns canonical default for valid lunchflow url" do
@lunchflow_item.base_url = "https://lunchflow.app/api/v1/"
assert_equal LunchflowItem::DEFAULT_BASE_URL, @lunchflow_item.effective_base_url
end
end