Skip to content

fix: validate artifact host for upload and download to address codeql ssrf alerts#207

Merged
gmegidish merged 1 commit intomainfrom
fix/codeql-ssrf-host-validation
Apr 27, 2026
Merged

fix: validate artifact host for upload and download to address codeql ssrf alerts#207
gmegidish merged 1 commit intomainfrom
fix/codeql-ssrf-host-validation

Conversation

@gmegidish
Copy link
Copy Markdown
Member

No description provided.

… ssrf alerts

use url.Hostname() (which codeql recognizes as a sanitizer) instead of url.Host,
extract the artifacts host into a constant, and apply the same exact-host check
to downloadFile that uploadFileToURL already had. closes codeql alerts #17 and #19.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Walkthrough

The change modifies URL validation logic in the remote handler for artifact uploads and downloads. A new file-local constant artifactsHost is introduced to define the expected hostname. URL validation is tightened to enforce HTTPS protocol and verify the hostname using the Hostname() method instead of Host. Error messages are updated to reflect these validation changes. Additionally, verbose logging is added to log the parsed download URL before executing the HTTP GET request.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive No pull request description was provided by the author, making it impossible to assess relevance to the changeset. Add a description explaining the SSRF vulnerability being addressed, the validation approach, and any testing performed to verify the fix.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding validation for artifact hosts in upload and download operations to address SSRF security alerts.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/codeql-ssrf-host-validation

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@devices/remote.go`:
- Line 235: The error message currently echoes the full presigned uploadURL (see
the fmt.Errorf that references artifactsHost and uploadURL) which leaks signed
query params; change the code to avoid logging or returning the full URL—parse
uploadURL (using url.Parse) and either log only safe parts (scheme and host
and/or path) or redact the query/fragment before including it in the error, or
simply reference artifactsHost and a short indicator like
"<redacted-presigned-url>" instead of the full uploadURL; apply the same
redaction approach to the other occurrences that reference uploadURL around the
fmt.Errorf calls at the same code sites.
- Line 289: The download call currently uses http.Get (resp, err :=
http.Get(parsed.String())) which has no timeout; replace it with a dedicated
HTTP client that enforces a timeout (e.g., reuse or create a downloadHTTPClient
with Timeout: 5*time.Minute consistent with uploadHTTPClient) and call
downloadHTTPClient.Get(parsed.String()) instead, ensuring any client variable
(downloadHTTPClient or uploadHTTPClient) is defined at package scope like
uploadFileToURL uses and that error handling and resp.Body handling remain
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 54bdcd3f-fbb9-4037-9f58-c8b903b4367d

📥 Commits

Reviewing files that changed from the base of the PR and between db3549d and ca6f345.

📒 Files selected for processing (1)
  • devices/remote.go

Comment thread devices/remote.go
if u.Scheme != "https" || u.Host != "mobilenexthq-artifacts.s3.us-west-2.amazonaws.com" {
return fmt.Errorf("upload URL must be https://mobilenexthq-artifacts.s3.us-west-2.amazonaws.com/..., got: %s", uploadURL)
if u.Scheme != "https" || u.Hostname() != artifactsHost {
return fmt.Errorf("upload URL must be https://%s/..., got: %s", artifactsHost, uploadURL)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not log or echo full presigned artifact URLs.

Line 235, Line 285, and Line 288 can expose signed query params in logs/errors. That leaks temporary credentials and weakens the security fix.

🔐 Proposed fix (redact URL details)
- return fmt.Errorf("upload URL must be https://%s/..., got: %s", artifactsHost, uploadURL)
+ return fmt.Errorf("upload URL must be https://%s/...", artifactsHost)

- return fmt.Errorf("download URL must be https://%s/..., got: %s", artifactsHost, downloadURL)
+ return fmt.Errorf("download URL must be https://%s/...", artifactsHost)

- utils.Verbose("downloading from %v", parsed)
+ utils.Verbose("downloading from host=%s path=%s", parsed.Hostname(), parsed.EscapedPath())

Also applies to: 285-285, 288-288

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@devices/remote.go` at line 235, The error message currently echoes the full
presigned uploadURL (see the fmt.Errorf that references artifactsHost and
uploadURL) which leaks signed query params; change the code to avoid logging or
returning the full URL—parse uploadURL (using url.Parse) and either log only
safe parts (scheme and host and/or path) or redact the query/fragment before
including it in the error, or simply reference artifactsHost and a short
indicator like "<redacted-presigned-url>" instead of the full uploadURL; apply
the same redaction approach to the other occurrences that reference uploadURL
around the fmt.Errorf calls at the same code sites.

Comment thread devices/remote.go

resp, err := http.Get(parsed.String()) //nolint:gosec // URL is validated above
utils.Verbose("downloading from %v", parsed)
resp, err := http.Get(parsed.String())
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify unbounded GET usage in Go files and confirm timeout-backed clients.
# Expected:
# 1) No remaining production-path `http.Get(...)` in download/upload flows.
# 2) Download and upload both use `http.Client{Timeout: ...}`.

rg -nP --type=go -C2 '\bhttp\.Get\s*\('
rg -nP --type=go -C2 'var\s+\w+HTTPClient\s*=\s*&http\.Client\s*\{\s*Timeout:'

Repository: mobile-next/mobilecli

Length of output: 1360


🏁 Script executed:

sed -n '220,295p' devices/remote.go

Repository: mobile-next/mobilecli

Length of output: 2213


Use an HTTP client with explicit timeout for the download request.

Line 289 uses http.Get, which uses the default client without a request timeout. A stalled connection can block this flow indefinitely. This mirrors the pattern already established in the file where uploadFileToURL uses uploadHTTPClient with a 5-minute timeout.

⏱️ Proposed fix (bounded download request)
+var downloadHTTPClient = &http.Client{Timeout: 5 * time.Minute}
+
 func downloadFile(downloadURL, outputPath string, cb *ScreenRecordCallbacks) error {
 	parsed, err := url.Parse(downloadURL)
 	if err != nil {
 		return fmt.Errorf("invalid download URL: %w", err)
 	}

 	if parsed.Scheme != "https" || parsed.Hostname() != artifactsHost {
 		return fmt.Errorf("download URL must be https://%s/..., got: %s", artifactsHost, downloadURL)
 	}

 	utils.Verbose("downloading from %v", parsed)
-	resp, err := http.Get(parsed.String())
+	resp, err := downloadHTTPClient.Get(parsed.String())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
resp, err := http.Get(parsed.String())
var downloadHTTPClient = &http.Client{Timeout: 5 * time.Minute}
func downloadFile(downloadURL, outputPath string, cb *ScreenRecordCallbacks) error {
parsed, err := url.Parse(downloadURL)
if err != nil {
return fmt.Errorf("invalid download URL: %w", err)
}
if parsed.Scheme != "https" || parsed.Hostname() != artifactsHost {
return fmt.Errorf("download URL must be https://%s/..., got: %s", artifactsHost, downloadURL)
}
utils.Verbose("downloading from %v", parsed)
resp, err := downloadHTTPClient.Get(parsed.String())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@devices/remote.go` at line 289, The download call currently uses http.Get
(resp, err := http.Get(parsed.String())) which has no timeout; replace it with a
dedicated HTTP client that enforces a timeout (e.g., reuse or create a
downloadHTTPClient with Timeout: 5*time.Minute consistent with uploadHTTPClient)
and call downloadHTTPClient.Get(parsed.String()) instead, ensuring any client
variable (downloadHTTPClient or uploadHTTPClient) is defined at package scope
like uploadFileToURL uses and that error handling and resp.Body handling remain
unchanged.

@gmegidish gmegidish merged commit f7c1a20 into main Apr 27, 2026
15 checks passed
@gmegidish gmegidish deleted the fix/codeql-ssrf-host-validation branch April 27, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant