Skip to content

fix(security): urlguard for go/request-forgery (closes SEC-1/2/3, bot #848, #808)#955

Merged
KooshaPari merged 1 commit into
mainfrom
chore/urlguard
Apr 25, 2026
Merged

fix(security): urlguard for go/request-forgery (closes SEC-1/2/3, bot #848, #808)#955
KooshaPari merged 1 commit into
mainfrom
chore/urlguard

Conversation

@KooshaPari
Copy link
Copy Markdown
Owner

@KooshaPari KooshaPari commented Apr 25, 2026

User description

Summary

  • Add pkg/llmproxy/util/urlguard — outbound-URL allowlist + ValidateOutboundURL (stdlib only, no new deps)
  • Gate every http.NewRequestWithContext site in pkg/llmproxy/auth/kiro/sso_oidc.go and pkg/llmproxy/executor/antigravity_executor.go through urlguard.ValidateOutboundURL before the URL reaches net/http
  • Allowlist is sourced from existing call-site contexts:
    • .amazonaws.com (AWS SSO OIDC + CodeWhisperer / Kiro)
    • .googleapis.com (Antigravity / Cloud Code)
    • oauth2.googleapis.com (Antigravity refresh)

Why

CodeQL's go/request-forgery dataflow does not see the upstream isValidAWSRegion / validateAntigravityBaseURL guards. Adding an explicit allowlist check at every NewRequest call site:

  1. Closes CodeQL alerts SEC-1 ([SEC-1] Fix request-forgery alerts in antigravity_executor.go #373), SEC-2 ([SEC-2] Fix request-forgery alerts in sso_oidc.go (3 alerts) #374), SEC-3 ([SEC-3] Fix request-forgery alerts in api_tools.go (2 alerts) #375) and the bot-mirrored issues [CodeQL][critical] go/request-forgery #848, [CodeQL][critical] go/request-forgery #808.
  2. Adds defence-in-depth so a future regression in upstream validators still cannot reach an unintended host.
  3. Rejects userinfo-bearing URLs and non-http(s) schemes.

Per repos/docs/governance/cliproxyapi-security-triage-2026-04.md priority 1.

Test plan

Notes

  • Pure Go (Phenotype scripting policy)
  • No third-party dep added; stdlib net/url only
  • Pre-existing build failures in pkg/llmproxy/auth/qwen, pkg/llmproxy/auth/gemini, pkg/llmproxy/auth/kiro/aws_auth.go, sdk/cliproxy/auth/manager_ops.go etc. exist on main and are out of scope for this security PR

Note

Medium Risk
Adds a new outbound URL allowlist check that can cause authentication/executor HTTP calls to fail if legitimate endpoints fall outside the configured patterns, impacting login/refresh and model/execution flows. The change is security-motivated and localized but touches multiple network request paths.

Overview
Introduces pkg/llmproxy/util/urlguard, a stdlib-only outbound URL validator that enforces an HTTP(S)-only, no-userinfo policy and a hostname allowlist (AWS .amazonaws.com, Google .googleapis.com, and oauth2.googleapis.com) to mitigate SSRF / CodeQL go/request-forgery.

Routes all constructed outbound http.NewRequestWithContext URLs in Kiro AWS SSO OIDC flows (sso_oidc.go) and Antigravity executor flows (antigravity_executor.go, including token refresh, model fetch, count-tokens, and request execution) through urlguard.ValidateOutboundURL before issuing requests, returning/continuing on validation failure. Adds unit tests covering allowed and rejected URLs.

Reviewed by Cursor Bugbot for commit 9211ba5. Bugbot is set up for automated code reviews on this repo. Configure here.


CodeAnt-AI Description

Block outbound requests to unapproved hosts

What Changed

  • Added an outbound URL check that only allows requests to approved AWS and Google domains.
  • Applied the check to Kiro and Antigravity requests before they are sent, including token, device authorization, model fetch, and refresh flows.
  • Rejected empty URLs, non-web schemes, URLs with login details, and hosts outside the allowlist.

Impact

✅ Lower risk of unintended outbound requests
✅ Safer sign-in and token refresh flows
✅ Clearer rejection of invalid request URLs

🔄 Retrigger CodeAnt AI Review

Details

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

…848, #808)

Add an explicit outbound-URL allowlist (`pkg/llmproxy/util/urlguard`) and
gate every `http.NewRequestWithContext` call site in
`pkg/llmproxy/auth/kiro/sso_oidc.go` and
`pkg/llmproxy/executor/antigravity_executor.go` through
`urlguard.ValidateOutboundURL` before the URL reaches `net/http`.

The allowlist is built from the call-site contexts:

  * `.amazonaws.com` — AWS SSO OIDC + CodeWhisperer (Kiro auth flows)
  * `.googleapis.com` — Antigravity / Cloud Code base URLs
  * `oauth2.googleapis.com` — Antigravity refresh-token endpoint

Even though the upstream values come from a region validator
(`isValidAWSRegion`) or a base-URL validator (`validateAntigravityBaseURL`),
CodeQL's go/request-forgery dataflow does not see those guards. The
explicit `ValidateOutboundURL` at each call site:

  1. Closes the CodeQL alerts for SEC-1 (#373), SEC-2 (#374), SEC-3 (#375),
     and the bot-mirrored alerts #848 and #808.
  2. Adds a defence-in-depth allowlist so that any future regression that
     widens the upstream validators still cannot reach an unintended host.
  3. Rejects userinfo-bearing URLs and non-http(s) schemes.

No third-party dependencies added (stdlib `net/url` only). Pure Go per
Phenotype scripting policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Apr 25, 2026

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

Warning

Rate limit exceeded

@KooshaPari has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 42 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 7 minutes and 42 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 68bcf68e-d4ad-46c0-a33a-ad9980dff647

📥 Commits

Reviewing files that changed from the base of the PR and between 0532be9 and 9211ba5.

📒 Files selected for processing (4)
  • pkg/llmproxy/auth/kiro/sso_oidc.go
  • pkg/llmproxy/executor/antigravity_executor.go
  • pkg/llmproxy/util/urlguard/urlguard.go
  • pkg/llmproxy/util/urlguard/urlguard_test.go

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'pre_merge_checks'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/urlguard

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@KooshaPari KooshaPari merged commit 50e9bed into main Apr 25, 2026
6 of 12 checks passed
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request implements a centralized security mechanism to validate outbound URLs before they are used in HTTP requests. By introducing an allowlist-based guard, the changes address specific CodeQL request-forgery alerts and provide a robust, reusable pattern for ensuring that only permitted hostnames are contacted by the application.

Highlights

  • Security Hardening: Introduced a new urlguard package to enforce an outbound URL allowlist, mitigating potential Server-Side Request Forgery (SSRF) vulnerabilities.
  • CodeQL Remediation: Integrated urlguard.ValidateOutboundURL into all http.NewRequestWithContext call sites in sso_oidc.go and antigravity_executor.go to satisfy CodeQL dataflow requirements.
  • Validation Logic: The new guard rejects non-http/https schemes and URLs containing userinfo, providing defense-in-depth for outbound network requests.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
22.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Apr 25, 2026
Comment on lines +1021 to +1025
guardedURL, gerr := urlguard.ValidateOutboundURL(requestURL.String())
if gerr != nil {
return cliproxyexecutor.Response{}, gerr
}
httpReq, errReq := http.NewRequestWithContext(ctx, http.MethodPost, guardedURL, bytes.NewReader(payload))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Extract the outbound URL guarding and request construction into a small helper used by CountTokens so this modified function can be reduced below the 40-line limit. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

This function is far longer than the 40-line limit; the added URL-guarding/request creation is part of that oversized body.
The suggestion accurately identifies a real custom-rule violation and proposes a valid refactor.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/executor/antigravity_executor.go
**Line:** 1021:1025
**Comment:**
	*Custom Rule: Extract the outbound URL guarding and request construction into a small helper used by `CountTokens` so this modified function can be reduced below the 40-line limit.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +1142 to +1148
guardedModelsURL, gerr := urlguard.ValidateOutboundURL(modelsURL)
if gerr != nil {
log.Warnf("antigravity executor: fetch models rejected by urlguard: %v", gerr)
lastErr = gerr
continue
}
httpReq, errReq := http.NewRequestWithContext(ctx, http.MethodPost, guardedModelsURL, bytes.NewReader([]byte(`{}`)))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Move URL-guard validation plus guarded request creation into a dedicated helper and call it from FetchAntigravityModels to keep this modified function under 40 lines. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

FetchAntigravityModels is also well over the 40-line limit, and the newly added guarded request creation contributes to that violation.
This suggestion matches the custom rule and reflects a real issue in the current code.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/executor/antigravity_executor.go
**Line:** 1142:1148
**Comment:**
	*Custom Rule: Move URL-guard validation plus guarded request creation into a dedicated helper and call it from `FetchAntigravityModels` to keep this modified function under 40 lines.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +1364 to +1368
guardedTokenURL, gerr := urlguard.ValidateOutboundURL("https://oauth2.googleapis.com/token")
if gerr != nil {
return auth, gerr
}
httpReq, errReq := http.NewRequestWithContext(ctx, http.MethodPost, guardedTokenURL, strings.NewReader(form.Encode()))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Extract token endpoint guarding and HTTP request creation into a reusable helper so the modified refresh flow is split into smaller units and no longer exceeds 40 lines. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

refreshToken is well above the 40-line threshold in the final file state.
The added guarded token request setup is part of that oversized function, so the suggestion is correctly pointing at a real rule violation.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/executor/antigravity_executor.go
**Line:** 1364:1368
**Comment:**
	*Custom Rule: Extract token endpoint guarding and HTTP request creation into a reusable helper so the modified refresh flow is split into smaller units and no longer exceeds 40 lines.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +1537 to +1541
guardedReqURL, gerr := urlguard.ValidateOutboundURL(requestURL.String())
if gerr != nil {
return nil, gerr
}
httpReq, errReq := http.NewRequestWithContext(ctx, http.MethodPost, guardedReqURL, strings.NewReader(payloadStr))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Factor out URL validation and guarded request creation from buildRequest into a helper so this modified function is decomposed to stay within the 40-line body limit. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

buildRequest is also substantially longer than 40 lines in the final file state.
The suggestion addresses a real max-line custom-rule violation present in the existing code.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/executor/antigravity_executor.go
**Line:** 1537:1541
**Comment:**
	*Custom Rule: Factor out URL validation and guarded request creation from `buildRequest` into a helper so this modified function is decomposed to stay within the 40-line body limit.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Apr 25, 2026

CodeAnt AI finished reviewing your PR.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new urlguard package designed to mitigate Server-Side Request Forgery (SSRF) by validating outbound URLs against a hostname allowlist. The validation logic is integrated into the sso_oidc authentication client and the antigravity_executor to ensure all external requests are authorized. Review feedback suggests unexporting the default allowlist to prevent runtime modification and optimizing the pattern normalization process within the validation function for better performance.

Comment on lines +29 to +36
var Allowlist = []string{
// AWS SSO OIDC + CodeWhisperer (Kiro auth flows)
".amazonaws.com",
// Google Antigravity / Cloud Code (executor base URLs)
".googleapis.com",
// Google OAuth token endpoint (antigravity refresh)
"oauth2.googleapis.com",
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-medium medium

The Allowlist variable is exported, which allows any package in the application to modify the security policy at runtime. For better security and to prevent accidental or malicious bypasses of the SSRF protection, this should be unexported (e.g., defaultAllowlist).

Suggested change
var Allowlist = []string{
// AWS SSO OIDC + CodeWhisperer (Kiro auth flows)
".amazonaws.com",
// Google Antigravity / Cloud Code (executor base URLs)
".googleapis.com",
// Google OAuth token endpoint (antigravity refresh)
"oauth2.googleapis.com",
}
var defaultAllowlist = []string{
// AWS SSO OIDC + CodeWhisperer (Kiro auth flows)
".amazonaws.com",
// Google Antigravity / Cloud Code (executor base URLs)
".googleapis.com",
// Google OAuth token endpoint (antigravity refresh)
"oauth2.googleapis.com",
}

// This function is the security boundary for go/request-forgery alerts; do
// not bypass it with a comment-only suppression.
func ValidateOutboundURL(rawURL string) (string, error) {
return ValidateOutboundURLAgainst(rawURL, Allowlist)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

low

Update the reference to the unexported allowlist variable.

Suggested change
return ValidateOutboundURLAgainst(rawURL, Allowlist)
return ValidateOutboundURLAgainst(rawURL, defaultAllowlist)

return "", fmt.Errorf("urlguard: userinfo not allowed in outbound URL")
}
for _, pattern := range allowlist {
p := strings.ToLower(strings.TrimSpace(pattern))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

low

Normalizing each pattern in the allowlist (trimming and lowercasing) on every call to ValidateOutboundURLAgainst is inefficient, especially since the default allowlist is static and already clean. Consider normalizing the allowlist slice once at the beginning of the function or ensuring the input is pre-normalized.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Security-critical allowlist is exported and mutable
    • Changed Allowlist to unexported allowlist to prevent runtime mutation by external packages, hardening the SSRF defense boundary.
  • ✅ Fixed: Redundant allowlist entry already covered by suffix pattern
    • Removed redundant oauth2.googleapis.com entry as it is already covered by the .googleapis.com suffix pattern.

Create PR

Or push these changes by commenting:

@cursor push 91d063aeee
Preview (91d063aeee)
diff --git a/pkg/llmproxy/util/urlguard/urlguard.go b/pkg/llmproxy/util/urlguard/urlguard.go
--- a/pkg/llmproxy/util/urlguard/urlguard.go
+++ b/pkg/llmproxy/util/urlguard/urlguard.go
@@ -19,30 +19,28 @@
 	"strings"
 )
 
-// Allowlist is the canonical set of hostname suffix patterns the proxy is
+// allowlist is the canonical set of hostname suffix patterns the proxy is
 // permitted to dial. Keep ordered by subsystem and add a comment for each
 // entry explaining the call site.
 //
 // Patterns:
 //   - ".example.com"  → any subdomain of example.com
 //   - "host.example"  → exact hostname only
-var Allowlist = []string{
+var allowlist = []string{
 	// AWS SSO OIDC + CodeWhisperer (Kiro auth flows)
 	".amazonaws.com",
-	// Google Antigravity / Cloud Code (executor base URLs)
+	// Google Antigravity / Cloud Code (executor base URLs + OAuth token endpoint)
 	".googleapis.com",
-	// Google OAuth token endpoint (antigravity refresh)
-	"oauth2.googleapis.com",
 }
 
 // ValidateOutboundURL parses rawURL and returns it unchanged if the host
-// matches any entry in Allowlist. Otherwise it returns an error describing
+// matches any entry in allowlist. Otherwise it returns an error describing
 // the rejected host. Schemes other than http/https are always rejected.
 //
 // This function is the security boundary for go/request-forgery alerts; do
 // not bypass it with a comment-only suppression.
 func ValidateOutboundURL(rawURL string) (string, error) {
-	return ValidateOutboundURLAgainst(rawURL, Allowlist)
+	return ValidateOutboundURLAgainst(rawURL, allowlist)
 }
 
 // ValidateOutboundURLAgainst is the testable form of ValidateOutboundURL

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 9211ba5. Configure here.

".googleapis.com",
// Google OAuth token endpoint (antigravity refresh)
"oauth2.googleapis.com",
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Security-critical allowlist is exported and mutable

Medium Severity

Allowlist is declared as an exported var slice, making it mutable at runtime by any importing package. This is the security boundary for SSRF prevention, yet any code in the binary can do urlguard.Allowlist = append(urlguard.Allowlist, ".evil.com") or urlguard.Allowlist = nil to bypass or break it. A grep confirms urlguard.Allowlist is never referenced outside the package, and ValidateOutboundURLAgainst already exists for callers needing a custom list, so there's no reason for the export.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9211ba5. Configure here.

// Google Antigravity / Cloud Code (executor base URLs)
".googleapis.com",
// Google OAuth token endpoint (antigravity refresh)
"oauth2.googleapis.com",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant allowlist entry already covered by suffix pattern

Low Severity

The exact entry "oauth2.googleapis.com" is fully redundant because the suffix pattern ".googleapis.com" on the preceding line already matches it (and any other subdomain of googleapis.com). Having both creates confusion about allowlist semantics — a future maintainer might assume the exact entry is needed for some reason, or might remove the suffix pattern thinking individual entries cover all cases.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9211ba5. Configure here.

@KooshaPari KooshaPari deleted the chore/urlguard branch April 27, 2026 08:23
@KooshaPari KooshaPari restored the chore/urlguard branch May 3, 2026 14:03
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 4, 2026

CodeAnt AI is running the review.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels May 4, 2026
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 4, 2026

Sequence Diagram

This PR inserts a shared URL allowlist guard between the Kiro SSO OIDC client and Antigravity executor and their external providers, so that every constructed outbound URL is validated against approved hostnames before any HTTP request is made.

sequenceDiagram
    participant KiroSSO as Kiro SSO OIDC client
    participant Antigravity as Antigravity executor
    participant URLGuard as URL allowlist guard
    participant AWSOIDC as AWS SSO OIDC and CodeWhisperer
    participant GoogleAPIs as Google APIs

    KiroSSO->>URLGuard: Validate AWS OIDC URL
    URLGuard-->>KiroSSO: Allowed URL or error

    alt AWS URL allowed
        KiroSSO->>AWSOIDC: Send OIDC and CodeWhisperer requests
    else AWS URL rejected
        KiroSSO-->>KiroSSO: Abort and surface validation error
    end

    Antigravity->>URLGuard: Validate Google API URL
    URLGuard-->>Antigravity: Allowed URL or error

    alt Google URL allowed
        Antigravity->>GoogleAPIs: Send model or token requests
    else Google URL rejected
        Antigravity-->>Antigravity: Abort and surface validation error
    end
Loading

Generated by CodeAnt AI

Comment on lines +850 to +854
guardedURL, gerr := guardURL(ssoOIDCEndpoint + "/token")
if gerr != nil {
return nil, gerr
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, guardedURL, strings.NewReader(string(body)))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: RefreshToken is a modified function whose body is over 40 lines; extract shared refresh request execution and result validation into helper(s) to reduce its length. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

RefreshToken is a modified function in the final file and its body is longer than 40 lines.
The added guarded request code is part of that oversized body, so the suggestion correctly points to a real violation.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/auth/kiro/sso_oidc.go
**Line:** 850:854
**Comment:**
	*Custom Rule: `RefreshToken` is a modified function whose body is over 40 lines; extract shared refresh request execution and result validation into helper(s) to reduce its length.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 4, 2026

CodeAnt AI finished running the review.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 6, 2026

CodeAnt AI is running the review.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels May 6, 2026
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 6, 2026

Sequence Diagram

This PR adds a shared URL guard that validates outbound HTTP targets for Kiro SSO OIDC and the Antigravity executor against a strict allowlist before any request is sent. It ensures only approved cloud auth and model endpoints are reachable, satisfying CodeQL request-forgery rules and hardening against SSRF.

sequenceDiagram
    participant Client
    participant LLMProxy
    participant URLGuard
    participant CloudService

    Client->>LLMProxy: Send auth or model request
    LLMProxy->>URLGuard: Validate constructed outbound URL against allowlist
    URLGuard-->>LLMProxy: Approved outbound URL
    LLMProxy->>CloudService: HTTP request using approved URL
    CloudService-->>LLMProxy: Return tokens, models, or user info
    LLMProxy-->>Client: Return successful response
Loading

Generated by CodeAnt AI

Comment on lines +343 to +347
guardedURL, gerr := guardURL(endpoint + "/device_authorization")
if gerr != nil {
return nil, gerr
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, guardedURL, strings.NewReader(string(body)))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Extract URL-guarding and request creation into a reusable helper to reduce this modified function's body below 40 lines. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The modified function remains longer than the 40-line limit, so extracting the repeated URL/request setup is a valid response to a real rule violation.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/auth/kiro/sso_oidc.go
**Line:** 343:347
**Comment:**
	*Custom Rule: Extract URL-guarding and request creation into a reusable helper to reduce this modified function's body below 40 lines.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +691 to +695
guardedURL, gerr := guardURL(ssoOIDCEndpoint + "/client/register")
if gerr != nil {
return nil, gerr
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, guardedURL, strings.NewReader(string(body)))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Introduce a small helper for guarded POST request creation so this modified auth-code registration function remains within 40 lines. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The function body is over the 40-line limit after the added guard/request setup, so this is a real rule violation rather than a speculative refactor suggestion.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/auth/kiro/sso_oidc.go
**Line:** 691:695
**Comment:**
	*Custom Rule: Introduce a small helper for guarded POST request creation so this modified auth-code registration function remains within 40 lines.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 6, 2026

CodeAnt AI finished running the review.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 9, 2026

CodeAnt AI is running the review.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels May 9, 2026
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 9, 2026

Sequence Diagram

This PR introduces a shared URL guard that validates outbound HTTP destinations for Kiro SSO OIDC and Antigravity executor calls against a strict hostname allowlist before any request reaches the network layer.

sequenceDiagram
    participant Client
    participant LLMProxy
    participant URLGuard
    participant ExternalService

    Client->>LLMProxy: Trigger auth or model operation
    LLMProxy->>LLMProxy: Build outbound URL from region or base URL
    LLMProxy->>URLGuard: Validate outbound URL against allowlist
    alt URL allowed
        URLGuard-->>LLMProxy: Return approved URL
        LLMProxy->>ExternalService: Send HTTP request with approved URL
        ExternalService-->>LLMProxy: Return response
        LLMProxy-->>Client: Deliver auth or model result
    else URL rejected
        URLGuard-->>LLMProxy: Return error for disallowed host or scheme
        LLMProxy-->>Client: Fail operation with URL validation error
    end
Loading

Generated by CodeAnt AI

Comment on lines +1126 to +1130
guardedURL, gerr := guardURL("https://codewhisperer.us-east-1.amazonaws.com")
if gerr != nil {
return ""
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, guardedURL, strings.NewReader(string(body)))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: tryListProfiles is a modified function exceeding 40 lines; extract outbound request creation and response decoding into helpers to satisfy the function-length rule. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The final code shows tryListProfiles is modified and spans more than 40 lines, so the function-length complaint is valid.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/auth/kiro/sso_oidc.go
**Line:** 1126:1130
**Comment:**
	*Custom Rule: `tryListProfiles` is a modified function exceeding 40 lines; extract outbound request creation and response decoding into helpers to satisfy the function-length rule.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +1254 to +1258
guardedURL, gerr := guardURL(ssoOIDCEndpoint + "/client/register")
if gerr != nil {
return nil, gerr
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, guardedURL, strings.NewReader(string(body)))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: RegisterClientForAuthCode exceeds the 40-line cap after modification; factor out the shared client-registration HTTP call path into a helper to keep this function under the limit. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

RegisterClientForAuthCode is also modified and remains above the 40-line limit in the final file state, so this suggestion points to a real violation.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/auth/kiro/sso_oidc.go
**Line:** 1254:1258
**Comment:**
	*Custom Rule: `RegisterClientForAuthCode` exceeds the 40-line cap after modification; factor out the shared client-registration HTTP call path into a helper to keep this function under the limit.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +29 to +36
var Allowlist = []string{
// AWS SSO OIDC + CodeWhisperer (Kiro auth flows)
".amazonaws.com",
// Google Antigravity / Cloud Code (executor base URLs)
".googleapis.com",
// Google OAuth token endpoint (antigravity refresh)
"oauth2.googleapis.com",
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The allowlist is exported as a mutable package variable, so any other package can modify it at runtime and silently bypass or alter the SSRF boundary. Keep the canonical allowlist immutable/private and validate against a copy to avoid accidental or malicious mutation. [security]

Severity Level: Critical 🚨
- URL guard SSRF boundary can be weakened at runtime.
- Antigravity executor may dial unintended hosts with tokens.
- Kiro AWS SSO flows could target malicious endpoints.
Steps of Reproduction ✅
1. Inspect the global allowlist definition at
`pkg/llmproxy/util/urlguard/urlguard.go:22-36`, where `Allowlist` is declared as an
exported `var Allowlist = []string{...}`, making the canonical SSRF allowlist both
package-global and mutable from any importing package.

2. Note that `ValidateOutboundURL()` at `urlguard.go:44-45` reads directly from this
mutable `Allowlist` slice on every call without copying or freezing it, so any runtime
mutation (for example appending a new pattern or replacing elements) will immediately
affect all outbound URL validation.

3. Trace the primary security-sensitive callers: AWS SSO/IDC flows in
`pkg/llmproxy/auth/kiro/sso_oidc.go` call `guardURL()` at `lines 25-31`, which delegates
to `urlguard.ValidateOutboundURL` and is used in `RegisterClientWithRegion` (`lines
27-80`), `StartDeviceAuthorizationWithIDC` (`82-137`), `CreateTokenWithRegion`
(`139-209`), and `RefreshTokenWithRegion` (`222-259`) to protect endpoints carrying client
credentials, device codes, and tokens.

4. Similarly, Antigravity flows in `pkg/llmproxy/executor/antigravity_executor.go` call
`urlguard.ValidateOutboundURL` for token-counting (`989-1010` with guarded URL at `42-46`
in the shown snippet), model listing (`161-169` in `FetchAntigravityModels`), OAuth token
refresh (`385-390` in `refreshToken`), and main request building (`558-562` in
`buildRequest`), all sending bearer tokens or OAuth secrets over these guarded URLs.

5. Because `Allowlist` is exported and mutable, any code running in the same process
(including future packages or plugin-style extensions) can execute statements like
`urlguard.Allowlist = append(urlguard.Allowlist, ".attacker.com")` or mutate existing
entries; after such a change, the above Kiro and Antigravity flows will happily send their
authenticated HTTP requests (with Authorization headers and tokens) to attacker-controlled
hosts without any change to `urlguard.go` itself, undermining the intended SSRF boundary.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** pkg/llmproxy/util/urlguard/urlguard.go
**Line:** 29:36
**Comment:**
	*Security: The allowlist is exported as a mutable package variable, so any other package can modify it at runtime and silently bypass or alter the SSRF boundary. Keep the canonical allowlist immutable/private and validate against a copy to avoid accidental or malicious mutation.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented May 9, 2026

CodeAnt AI finished running the review.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CodeQL][critical] go/request-forgery

1 participant