Skip to content

Comments

security: implement deceptive URL detection and Punycode disclosure#19287

Closed
ehedlund wants to merge 4 commits intogoogle-gemini:mainfrom
ehedlund:url-security
Closed

security: implement deceptive URL detection and Punycode disclosure#19287
ehedlund wants to merge 4 commits intogoogle-gemini:mainfrom
ehedlund:url-security

Conversation

@ehedlund
Copy link
Contributor

Summary

This PR implements security protections against deceptive URLs (homograph attacks) in tool confirmations.

Details

  • Detection Utility: Added urlSecurityUtils.ts providing isDeceptiveUrl and getDeceptiveUrlDetails using WHATWG URL parsing.
  • Deceptive URL Warning: Integrated a persistent, high-visibility warning block in ToolConfirmationMessage.tsx that reveals the Punycode (actual) identity of suspicious URLs.
  • Unicode-first Display: Updated the fetch list in confirmations to show Unicode hostnames for user context, while the warning block handles the security disclosure.
  • Rigorous Layout: Implemented calculateWrappedHeight to ensure security warnings are always fully visible and correctly sized within the confirmation dialog.
  • Terminal Safety: Standardized on "Deceptive URL" terminology and removed emojis that could interfere with terminal border rendering.

Related Issues

Addresses URL security and homograph protection.

How to Validate

  1. Unit Tests: npm test -w @google/gemini-cli -- src/ui/utils/urlSecurityUtils.test.ts
  2. Integration Tests: npm test -w @google/gemini-cli -- src/ui/components/messages/ToolConfirmationMessage.test.tsx
  3. Manual Verification:
    • Trigger a tool confirmation containing a deceptive URL (e.g., using a Cyrillic 'e').
    • Verify the prominent warning block appears with "Original" and "Actual Host (Punycode)" fields.

@ehedlund ehedlund requested a review from a team as a code owner February 17, 2026 21:57
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ehedlund, 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 significantly bolsters the security of tool confirmations by introducing comprehensive mechanisms to detect and clearly disclose deceptive URLs, protecting users from homograph attacks. It ensures that potentially malicious links are highlighted with their true Punycode form, while also improving the general readability of legitimate Unicode URLs. Additionally, the changes enhance command clarity by adding source labels to descriptions, providing users with better context about where commands originate.

Highlights

  • Deceptive URL Detection & Disclosure: Implemented robust detection for deceptive URLs (homograph attacks) and integrated a prominent warning block in tool confirmations that reveals the actual Punycode identity of suspicious URLs.
  • Unicode URL Display: Updated the display of URLs in confirmation messages to show Unicode hostnames, providing better user context while the warning block handles security disclosure.
  • Dynamic UI Layout for Warnings: Introduced a utility function, calculateWrappedHeight, to ensure security warnings are always fully visible and correctly sized within the terminal UI, adapting to available space.
  • Standardized Terminology and Rendering: Standardized on 'Deceptive URL' terminology and removed emojis from warnings to prevent interference with terminal border rendering.
  • Command Source Labeling: Enhanced command descriptions by prepending a source label (e.g., [username], [project-name], [extension-name]) for improved clarity and context, with fallback mechanisms for retrieving user information.
Changelog
  • packages/cli/src/services/FileCommandLoader.test.ts
    • Imported node:os for mocking user information.
    • Mocked os.userInfo to control username in tests.
    • Updated command description assertions to include the [mock-user] prefix.
    • Added new test suite for sourceLabel Assignment covering user, project, and extension commands, including fallback logic for os.userInfo() and Windows paths.
  • packages/cli/src/services/FileCommandLoader.ts
    • Imported node:os.
    • Added sourceLabel property to the CommandDirectory interface.
    • Implemented getUsername method to retrieve the OS username or fall back to environment variables.
    • Modified getCommandDirectories to assign appropriate sourceLabel (username, project root basename, or extension name) to command directories.
    • Updated parseAndAdaptFile to accept and utilize the sourceLabel for command descriptions.
    • Adjusted command description formatting to prepend the sourceLabel.
  • packages/cli/src/ui/components/messages/ToolConfirmationMessage.test.tsx
    • Added test cases to verify the display of WarningMessage for deceptive URLs in 'info' type confirmations.
    • Included test cases to confirm WarningMessage for deceptive URLs found in 'exec' type commands.
    • Added a test to ensure multiple deceptive URLs are aggregated into a single warning message.
  • packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
    • Imported getPlainTextLength from InlineMarkdownRenderer.js.
    • Imported WarningMessage, getDeceptiveUrlDetails, toUnicodeUrl, and DeceptiveUrlDetails for URL security features.
    • Introduced calculateWrappedHeight function to determine the display height of wrapped text.
    • Implemented useMemo hook to detect deceptive URLs within confirmation details and generate a formatted warning text.
    • Updated availableBodyContentHeight calculation to dynamically account for the height of the deceptive URL warning message.
    • Modified the useMemo hook for question, bodyContent, and options to also return securityWarnings.
    • Rendered the securityWarnings component conditionally before the main question.
    • Applied toUnicodeUrl to URLs displayed in 'info' type confirmations.
  • packages/cli/src/ui/utils/urlSecurityUtils.test.ts
    • Added a new test file for urlSecurityUtils.
    • Included tests for toUnicodeUrl covering Punycode conversion, URL object handling, complex URLs, and edge cases.
    • Added tests for isDeceptiveUrl to check for ASCII, non-ASCII, and homoglyph URLs.
    • Implemented tests for getDeceptiveUrlDetails to verify extraction of original and Punycode URLs for deceptive cases, and null for safe URLs.
  • packages/cli/src/ui/utils/urlSecurityUtils.ts
    • Added a new utility file for URL security.
    • Defined DeceptiveUrlDetails interface.
    • Implemented containsDeceptiveMarkers to identify Punycode or non-ASCII characters in hostnames.
    • Provided toUnicodeUrl function to convert Punycode hostnames to their Unicode representation.
    • Implemented getDeceptiveUrlDetails to return structured information about deceptive URLs.
    • Implemented isDeceptiveUrl to perform a boolean check for deceptive URLs.
Activity
  • No specific activity (comments, reviews, progress updates) has been recorded for this pull request yet.
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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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.

Copy link
Contributor

@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 valuable security feature to detect and warn about deceptive URLs (homograph attacks) in tool confirmations, enhancing user safety. The implementation includes a new utility for URL analysis, integrates warnings into the UI, and correctly adjusts the layout to accommodate these warnings. The PR also refactors command loading to include source labels in descriptions. My review focuses on the completeness of the new security feature. I've identified that the URL scanning is not applied to all relevant confirmation types, which could leave some attack vectors open. The suggestion to extend the scanning to edit and ask_user confirmations for more robust protection aligns with the principle of treating all external data as untrusted and applying validation at the point of use.

Comment on lines +129 to +148
const deceptiveUrlWarnings = useMemo(() => {
const urls: string[] = [];
if (confirmationDetails.type === 'info' && confirmationDetails.urls) {
urls.push(...confirmationDetails.urls);
} else if (confirmationDetails.type === 'exec') {
const commands =
confirmationDetails.commands && confirmationDetails.commands.length > 0
? confirmationDetails.commands
: [confirmationDetails.command];
for (const cmd of commands) {
const matches = cmd.match(/https?:\/\/[^\s"'`<>]+/g);
if (matches) urls.push(...matches);
}
}

const uniqueUrls = Array.from(new Set(urls));
return uniqueUrls
.map(getDeceptiveUrlDetails)
.filter((d): d is DeceptiveUrlDetails => d !== null);
}, [confirmationDetails]);
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The deceptive URL detection currently only covers info and exec confirmation types. However, other types like edit and ask_user can also display model-generated content that might contain deceptive URLs (e.g., in a file diff or a user prompt). To ensure comprehensive security, the detection should be extended to these types as well.

  const deceptiveUrlWarnings = useMemo(() => {
    const URL_REGEX = /https?:\/\/[^\s"'`<>]+/g;
    const urls: string[] = [];

    if (confirmationDetails.type === 'info' && confirmationDetails.urls) {
      urls.push(...confirmationDetails.urls);
    } else if (confirmationDetails.type === 'exec') {
      const commands =
        confirmationDetails.commands && confirmationDetails.commands.length > 0
          ? confirmationDetails.commands
          : [confirmationDetails.command];
      for (const cmd of commands) {
        const matches = cmd.match(URL_REGEX);
        if (matches) urls.push(...matches);
      }
    } else if (
      confirmationDetails.type === 'edit' &&
      confirmationDetails.fileDiff
    ) {
      const matches = confirmationDetails.fileDiff.match(URL_REGEX);
      if (matches) urls.push(...matches);
    } else if (
      confirmationDetails.type === 'ask_user' &&
      confirmationDetails.questions
    ) {
      for (const q of confirmationDetails.questions) {
        const matches = q.question.match(URL_REGEX);
        if (matches) urls.push(...matches);
      }
    }

    const uniqueUrls = Array.from(new Set(urls));
    return uniqueUrls
      .map(getDeceptiveUrlDetails)
      .filter((d): d is DeceptiveUrlDetails => d !== null);
  }, [confirmationDetails]);
References
  1. This suggestion aligns with the principle of defense-in-depth by treating model-generated content and user prompts as untrusted data, requiring proper validation (deceptive URL detection) at the point of use, even if it's believed to be filtered upstream.

@ehedlund
Copy link
Contributor Author

Closing in favor of #19288 which is based on main and excludes unrelated commits.

@ehedlund ehedlund closed this Feb 17, 2026
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