Skip to content

fix: harden URL and path construction across helper modules#133

Open
NeekChaw wants to merge 1 commit intogoogleworkspace:mainfrom
NeekChaw:fix/harden-url-path-construction
Open

fix: harden URL and path construction across helper modules#133
NeekChaw wants to merge 1 commit intogoogleworkspace:mainfrom
NeekChaw:fix/harden-url-path-construction

Conversation

@NeekChaw
Copy link

@NeekChaw NeekChaw commented Mar 5, 2026

Closes #87

Summary

Audit of helper modules found several places where user-provided values are interpolated into URLs or file paths via format! without going through encode_path_segment() or validate_resource_name().

Changes

src/discovery.rs

  • Add validate_discovery_id() — only allows [a-zA-Z0-9._-] for service names/versions. Prevents path traversal in the local cache file path and injection in Discovery Document endpoint URLs.
  • Validate service and version at entry to fetch_discovery_document().
  • Move version query parameter in the alt-URL code path to reqwest .query() instead of string interpolation.

src/helpers/modelarmor.rs

  • Call validate_resource_name() on --template in handle_sanitize() and build_sanitize_request_data() before building URLs.
  • Validate --project, --location, --template-id in parse_create_template_args().
  • Use encode_path_segment() for templateId in build_create_template_url().

src/helpers/gmail/watch.rs

  • Extract message-URL building to build_message_url() using encode_path_segment() on the message ID.
  • Switch msg_format to reqwest .query() builder instead of string interpolation.

Testing

Added 15 new unit tests (happy-path + error-path) covering each fix:

  • 6 tests for validate_discovery_id in discovery.rs
  • 5 tests for resource name/template validation in modelarmor.rs
  • 4 tests for build_message_url in watch.rs

@NeekChaw NeekChaw requested a review from jpoehnelt as a code owner March 5, 2026 07:15
@changeset-bot
Copy link

changeset-bot bot commented Mar 5, 2026

🦋 Changeset detected

Latest commit: 4ecdc98

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gemini-code-assist
Copy link
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@google-cla
Copy link

google-cla bot commented Mar 5, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@NeekChaw
Copy link
Author

NeekChaw commented Mar 5, 2026

@googlebot I signed it!

@jpoehnelt jpoehnelt added area: http cla: no This human has *not* signed the Contributor License Agreement. complexity: medium Moderate change, some review needed labels Mar 5, 2026
@jpoehnelt
Copy link
Member

please fix the conflicts

@jpoehnelt
Copy link
Member

/gemini review

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 does a great job of hardening URL and path construction across several modules by introducing validation and proper encoding for user-provided inputs. The changes significantly improve the security posture of the application against path traversal and injection attacks. I've found one area in the new validation logic in discovery.rs where the check can be made more robust to cover additional edge cases for invalid identifiers. My specific feedback is in the comment below.

src/discovery.rs Outdated
Comment on lines +204 to +207
// Reject dot-only segments that could act as a traversal (e.g. "..")
if s.split('.').any(|seg| seg.is_empty()) && s.starts_with('.') {
anyhow::bail!("{label} '{s}' must not start with '.'");
}
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 current validation for dot-separated identifiers is not comprehensive enough. It correctly rejects identifiers starting with . (like .foo, ., and ..), but it fails to reject other invalid sequences such as foo..bar or foo.. When interpolated into a hostname like {service}.googleapis.com, these would result in invalid domain names (foo..bar.googleapis.com or foo..googleapis.com).

A more robust approach is to reject any empty segment that results from splitting the string by ..

    // Reject any empty dot-separated segments, which are invalid in hostnames
    // and can be used for path traversal (e.g. '..', '.foo', 'foo.').
    if s.split('.').any(str::is_empty) {
        anyhow::bail!(
            "{label} '{s}' contains invalid dot-sequences (e.g. '..', leading/trailing '.', or empty segments)"
        );
    }

@NeekChaw NeekChaw force-pushed the fix/harden-url-path-construction branch from ee3609f to 8bf9b14 Compare March 6, 2026 01:03
@googleworkspace-bot googleworkspace-bot added area: discovery area: core Core CLI parsing, commands, error handling, utilities and removed area: http labels Mar 6, 2026
@googleworkspace-bot
Copy link
Collaborator

/gemini review

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 important security hardening by validating user-provided values used in URL and file path construction, which helps prevent path traversal and injection attacks. The changes are well-implemented across the discovery, gmail, and modelarmor modules. I've identified a couple of instances of redundant validation in src/helpers/modelarmor.rs that should be removed to improve code clarity and maintainability.

Comment on lines +321 to +323
// Validate template resource name before using it in URLs (defense-in-depth;
// prevents injection even when the CLI is invoked by an untrusted agent).
crate::validate::validate_resource_name(template)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This validation is redundant. The template variable is assigned the result of crate::validate::validate_resource_name(template_raw)? on line 319, so it has already been validated. This second validation call is unnecessary and can be removed.

Comment on lines +355 to +358
// Validate inputs before embedding them in URLs.
crate::validate::validate_resource_name(&project)?;
crate::validate::validate_resource_name(&location)?;
crate::validate::validate_resource_name(&template_id)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This block of validations is redundant. The project, location, and template_id variables are created from the results of validate_resource_name on lines 349, 351, and 353 respectively, so they have already been validated. This block can be removed.

@NeekChaw NeekChaw force-pushed the fix/harden-url-path-construction branch from 8bf9b14 to 4ecdc98 Compare March 6, 2026 02:06
…oogleworkspace#87)

Audit of helper modules found several places where user-provided values are
interpolated into URLs or file paths via format! without going through
encode_path_segment() or validate_resource_name().

Changes:

src/discovery.rs
- Add validate_discovery_id() that allows only [a-zA-Z0-9._-] for service
  names and version strings, preventing path traversal in the cache directory
  and injection in Discovery Document endpoint URLs.
- Validate service and version at the entry point of fetch_discovery_document.
- Move the version query parameter in the alt-URL code path to reqwest .query().

src/helpers/modelarmor.rs
- Call validate_resource_name() on --template before embedding it in URLs
  in handle_sanitize() and build_sanitize_request_data().
- Validate --project, --location, --template-id in parse_create_template_args().
- Use encode_path_segment() for templateId in build_create_template_url().

src/helpers/gmail/watch.rs
- Extract message-URL building to build_message_url() using encode_path_segment
  on the message ID (prevents path/query injection from API-supplied IDs).
- Switch msg_format to reqwest .query() builder instead of string interpolation.

Adds 15 new unit tests (happy-path + error-path) for each fix.
@googleworkspace-bot
Copy link
Collaborator

/gemini review

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 does a great job of hardening URL and path construction across several modules, which is a significant security improvement. The introduction of validation for user-provided values and the use of safer URL-building APIs effectively reduce the risk of injection and path traversal vulnerabilities. However, I've identified a critical issue in src/helpers/modelarmor.rs where project and location IDs are being over-encoded, which will likely cause API calls to fail. Please see my detailed comment.

Comment on lines 377 to 379
format!(
"{base}/{parent}/templates?templateId={}",
crate::validate::encode_path_segment(&config.template_id)
"{base}/{parent}/templates?templateId={template_id_encoded}"
)
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The parent variable used in this format! macro is constructed on line 373 using project and location values that have been overly-encoded on lines 371-372. Using encode_path_segment on them incorrectly escapes valid characters like hyphens (e.g., us-central1 becomes us%2Dcentral1), which will likely cause the API call to fail. Since these values are validated in parse_create_template_args, they should be safe to be used directly in the URL path. Please remove the encode_path_segment calls for project and location.

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

Labels

area: core Core CLI parsing, commands, error handling, utilities area: discovery cla: no This human has *not* signed the Contributor License Agreement. complexity: medium Moderate change, some review needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Harden URL and path construction across helper modules

3 participants