Skip to content

fix(security): cap Retry-After sleep and sanitize mimeType in uploads#448

Open
anshul-garg27 wants to merge 6 commits intogoogleworkspace:mainfrom
anshul-garg27:fix/cap-retry-after-sleep
Open

fix(security): cap Retry-After sleep and sanitize mimeType in uploads#448
anshul-garg27 wants to merge 6 commits intogoogleworkspace:mainfrom
anshul-garg27:fix/cap-retry-after-sleep

Conversation

@anshul-garg27
Copy link
Contributor

Summary

Two security hardening fixes for agent-facing attack surfaces:

1. Cap Retry-After sleep to 60 seconds (Critical)

A hostile or compromised API server can return Retry-After: 4294967295 in a 429 response, causing the CLI process to sleep for ~136 billion years. This is a denial-of-service vector, especially dangerous in unattended AI agent workflows where the process runs without human supervision.

Fix: Add .min(60) cap on the parsed Retry-After value in send_with_retry().

2. Sanitize mimeType in multipart upload headers (High)

The user-supplied mimeType field from --json body metadata is embedded directly into a MIME Content-Type header:

Content-Type: {media_mime}\r\n\r\n

A crafted mimeType like text/plain\r\nX-Injected: malicious could inject arbitrary MIME headers into the outbound multipart request body.

Fix: Strip \r and \n characters from media_mime before header construction.

Test plan

  • Added test verifying retry cap clamps large values to 60
  • Added test verifying normal values pass through unchanged
  • Existing client and executor tests continue to pass

@changeset-bot
Copy link

changeset-bot bot commented Mar 12, 2026

🦋 Changeset detected

Latest commit: bb77df7

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

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 introduces two critical security enhancements to the CLI's agent-facing attack surfaces. It addresses a potential denial-of-service vulnerability by capping Retry-After sleep durations and mitigates a header injection risk by sanitizing user-provided mimeType values during multipart uploads. These changes improve the robustness and security of the application, especially in automated AI agent workflows.

Highlights

  • Retry-After Sleep Cap: Implemented a 60-second cap on the Retry-After header value to prevent denial-of-service attacks where a malicious server could cause the CLI process to sleep indefinitely, especially in AI agent workflows.
  • mimeType Sanitization: Stripped carriage return and newline characters from user-supplied mimeType values in multipart upload headers to prevent MIME header injection vulnerabilities.
Changelog
  • .changeset/fix-retry-after-and-mime-injection.md
    • Added a new changeset file documenting the security fixes for Retry-After and mimeType sanitization.
  • src/client.rs
    • Introduced a MAX_RETRY_DELAY_SECS constant set to 60 seconds.
    • Applied a .min(MAX_RETRY_DELAY_SECS) cap to the parsed Retry-After header value.
    • Added a new test case retry_after_cap_prevents_unbounded_sleep to verify the Retry-After cap functionality.
  • src/executor.rs
    • Modified the build_multipart_body function to filter out carriage return (\r) and newline (\n) characters from the media_mime string before header construction.
Activity
  • The author added a test to verify the Retry-After cap correctly clamps large values to 60 seconds.
  • A test was added to confirm that normal Retry-After values below the cap pass through unchanged.
  • Existing client and executor tests were confirmed to continue passing.
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 Generative AI Prohibited Use Policy, 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 two important security hardening fixes. The first change caps the Retry-After sleep duration to prevent a potential denial-of-service attack, and the second sanitizes the mimeType in multipart uploads to prevent MIME header injection. The implementations for both fixes are correct. I've added one comment regarding the test for the Retry-After cap to make it more robust.

@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 two important security fixes for denial-of-service and header injection vulnerabilities. The implementations appear correct and effectively address the described issues. My review feedback focuses on improving the test coverage for these security-critical changes. Adding more robust tests will help ensure these fixes are reliable and prevent future regressions.

@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 two important security hardening fixes: capping the Retry-After sleep duration to prevent denial-of-service, and sanitizing the mimeType in multipart uploads to prevent header injection. The changes are well-implemented and include relevant tests. My review includes two suggestions for further hardening: one to make the mimeType sanitization more comprehensive by filtering all control characters, and another to prevent a potential integer overflow in the retry delay calculation, making it more robust for future changes.

@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 two important security hardening fixes. The first caps the Retry-After sleep duration to prevent a potential denial-of-service attack. The second sanitizes the mimeType in multipart uploads to prevent MIME header injection. The changes are well-implemented and include appropriate tests. I have provided one suggestion to improve the code by avoiding an unnecessary string allocation.

@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 two security hardening fixes: capping the Retry-After sleep duration to prevent a denial-of-service, and sanitizing the mimeType in multipart uploads to prevent header injection. The changes are well-implemented and include relevant tests. I've found one potential issue in the retry logic where a bit shift could panic if the number of retries is significantly increased in the future. I've suggested a more robust implementation to prevent this.

@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 two important security hardening fixes. The first caps the Retry-After sleep duration to 60 seconds to prevent a potential denial-of-service attack, which is implemented cleanly by adding a .min() to the delay calculation. The second fix sanitizes the mimeType field in multipart uploads to prevent header injection by filtering out control characters. Both changes are well-implemented, include corresponding unit tests to verify the fixes, and effectively address the described vulnerabilities.

Two security fixes:

1. Cap Retry-After header value to 60 seconds. A hostile or
   compromised API server could send Retry-After: 4294967295 to hang
   the CLI process indefinitely. This is especially dangerous for AI
   agent workflows where the process runs unattended.

2. Strip CR/LF from user-supplied mimeType before embedding it in
   the multipart MIME header. A mimeType like "text/plain\r\nX-Evil:
   injected" could inject arbitrary MIME headers into the upload body.
Extract the constant from inside the function body to module level
so it's shared between production code and tests. Use the constant
in the test assertion instead of the magic number 60.
Address Gemini review feedback:
- Extract retry delay logic into a testable compute_retry_delay()
  function with 5 focused unit tests covering: large values, small
  values, missing header, unparseable header, and boundary values
- Add unit test for mimeType CRLF sanitization in multipart uploads
  to verify header injection prevention

All 590 tests pass locally.
- Use 1u64 << attempt to prevent potential i32 overflow on large
  attempt values
- Strip all control characters (not just CR/LF) from mimeType to
  prevent any control char injection in MIME headers
Pass the &str directly from HeaderValue::to_str() to compute_retry_delay
instead of cloning into an owned String.
Replace 1u64 << attempt with 2u64.saturating_pow(attempt) to prevent
panic if MAX_RETRIES is ever increased beyond 63.
@anshul-garg27 anshul-garg27 force-pushed the fix/cap-retry-after-sleep branch from 5fd6c34 to bb77df7 Compare March 13, 2026 20:31
@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 two important security hardening fixes: capping the Retry-After sleep duration to prevent denial-of-service, and sanitizing the mimeType in multipart uploads to prevent header injection. The changes are well-implemented and include relevant tests. I've identified a minor edge case in the mimeType sanitization where a user-provided mimeType consisting solely of control characters would result in an empty Content-Type header, and I've suggested a small improvement to handle this.

Comment on lines +773 to +776
let media_mime: String = media_mime_raw
.chars()
.filter(|c| !c.is_control())
.collect();
Copy link
Contributor

Choose a reason for hiding this comment

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

high

After sanitizing media_mime_raw by removing control characters, the resulting media_mime string could be empty (e.g., if the input was just "\r\n"). This would lead to an empty Content-Type header for the media part, which is likely not intended and might be rejected by the server. It would be more robust to fall back to the default "application/octet-stream" if the sanitized string is empty.

Suggested change
let media_mime: String = media_mime_raw
.chars()
.filter(|c| !c.is_control())
.collect();
let mut media_mime: String = media_mime_raw
.chars()
.filter(|c| !c.is_control())
.collect();
if media_mime.is_empty() {
media_mime.push_str("application/octet-stream");
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good edge case — added a fallback to application/octet-stream if the sanitized mime ends up empty

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants