Skip to content

Commit c0e8306

Browse files
rounak610claude
andcommitted
LOC-6727: validate source URL host before binary download
Mirror the host allowlist added in the Java and Python bindings (browserstack-local-java#99, browserstack-local-python#62). Refuse download endpoints that aren't HTTPS or whose host isn't browserstack.com / *.browserstack.com. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e04e287 commit c0e8306

1 file changed

Lines changed: 24 additions & 1 deletion

File tree

lib/browserstack/fetch_download_source_url.rb

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,29 @@ module BrowserStack
88
module FetchDownloadSourceUrl
99
BS_HOST = 'local.browserstack.com'.freeze
1010
ENDPOINT_PATH = '/binary/api/v1/endpoint'.freeze
11+
ALLOWED_DOWNLOAD_HOSTS = ['browserstack.com'].freeze
12+
ALLOWED_DOWNLOAD_HOST_SUFFIXES = ['.browserstack.com'].freeze
13+
14+
def self.validate_source_url(url)
15+
if url.nil? || url.to_s.empty?
16+
raise BrowserStack::LocalException.new('Refusing binary download: empty source URL')
17+
end
18+
uri = begin
19+
URI.parse(url)
20+
rescue URI::InvalidURIError
21+
raise BrowserStack::LocalException.new('Refusing binary download: malformed source URL')
22+
end
23+
unless uri.scheme == 'https'
24+
raise BrowserStack::LocalException.new('Refusing binary download from non-HTTPS source URL')
25+
end
26+
host = (uri.host || '').downcase
27+
if host.empty?
28+
raise BrowserStack::LocalException.new('Refusing binary download: source URL has no host')
29+
end
30+
return url if ALLOWED_DOWNLOAD_HOSTS.include?(host)
31+
return url if ALLOWED_DOWNLOAD_HOST_SUFFIXES.any? { |suffix| host.end_with?(suffix) }
32+
raise BrowserStack::LocalException.new("Refusing binary download: host '#{host}' is not in the allowed host list")
33+
end
1134

1235
def self.call(auth_token:, user_agent:, fallback: false, error_message: nil,
1336
proxy_host: nil, proxy_port: nil)
@@ -57,7 +80,7 @@ def self.call(auth_token:, user_agent:, fallback: false, error_message: nil,
5780
)
5881
end
5982

60-
endpoint
83+
validate_source_url(endpoint)
6184
end
6285
end
6386
end

0 commit comments

Comments
 (0)