CVE-2025-27221
NoneCVSS
—
EPSS
0.5%
Published
Mar 4, 2025
CISA due date
—
Cloudanix analysis
Some Ruby applications may accidentally send passwords embedded in web addresses to the wrong destination when building links.
- Exploitation
- Remote Unauthenticated
- Attacker needs
- None
- Complexity
- Moderate
- Impact
- Data Exposure
- Component
- Library
- Class
- Information Disclosure
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
The Ruby URI gem before 1.0.3 can incorrectly retain the userinfo portion of a URI, such as username, password, or token-like credentials embedded before the host, when URI.join, URI#merge, or URI#+ changes the destination host. As a result, code that combines a credential-bearing base URI with an attacker-controlled or cross-origin URI may unintentionally produce a URL where the original credentials are attached to a different host. If that URL is logged, redirected, fetched by an HTTP client, or exposed to downstream services, authentication material may be disclosed to an unintended party.
Why it matters to the business
Applications that construct outbound URLs using Ruby URI may leak embedded credentials to external or untrusted destinations, potentially exposing service passwords, API tokens, or internal integration credentials. The risk is highly application-dependent and the public exploitation signal is currently low, with no CISA KEV listing, no ransomware association, and low EPSS, but the issue has been public for over a year and should be remediated as part of dependency hygiene, especially in systems that handle URLs containing credentials.
How an attack unfolds
An attacker needs a code path where an application uses the affected Ruby URI methods to combine URLs and where at least one input can influence the target URI or host. The vulnerable application starts with a base URI that includes credentials in the userinfo component, for example a service URL containing a username and password. The attacker supplies, or causes the application to process, a URI that changes the host. In vulnerable versions, the merge operation may keep the original userinfo while replacing the host with the attacker-controlled host. If the application then performs an outbound request, follows a redirect, stores the generated URL, or emits it to logs or telemetry, the credentials can be sent to or observed by the attacker-controlled destination. This does not generally provide direct code execution; the primary outcome is credential disclosure that may enable follow-on access depending on what the leaked credentials protect.
How to fix it
Upgrade the Ruby URI gem to version 1.0.3 or later. For source-based consumers, apply the upstream fix at commit c13dfc2164bc4af31085e709ab348fdbd527013f or use a Ruby distribution that includes the patched URI gem. Update lockfiles and redeploy all applications that bundle the vulnerable gem. As defense in depth, avoid embedding credentials in URLs; store credentials separately and pass them through scoped authentication mechanisms such as headers or client configuration. Before merging or joining URLs, explicitly clear userinfo when the host changes, validate the final host against an allowlist, and prevent credentials from being forwarded across origins or redirects.
How to confirm the fix worked
Confirm runtime and packaged dependency versions show uri >= 1.0.3 in all Ruby applications, containers, build artifacts, and lockfiles. Validate with a regression test that merging a credential-bearing URI with a URI on a different host does not retain the original userinfo. Review dependency manifests such as Gemfile.lock, gemspec files, vendored gems, container SBOMs, and Ruby default/bundled gem versions. Exercise application flows that construct outbound URLs and verify that generated URLs do not contain username:password@ when the destination host differs from the original credential scope.
Typical attack path
- Identify a Ruby application or library path that uses URI.join, URI#merge, or URI#+ to construct URLs.
- Find or influence a flow where the base URL contains userinfo credentials such as username:password@host.
- Provide a URL or redirect target that changes the host to an attacker-controlled or observable domain.
- Trigger the vulnerable URI merge operation so the credentials are retained on the new host.
- Observe the leaked credentials through an inbound request, proxy log, application log, redirect target, or other telemetry.
- Use the exposed credentials for follow-on authentication attempts against the service they were intended to protect.
How to detect it
Investigate whether applications using vulnerable URI versions generated or requested URLs containing userinfo before an unexpected host. Useful sources include application logs, HTTP client debug logs, reverse proxy logs, egress proxy logs, DNS logs, outbound firewall logs, APM traces, error reporting systems, and centralized log stores. Look for URLs with the pattern scheme://username:password@host, especially where the host is external, newly observed, user-controlled, or inconsistent with the service that owns the credentials. Correlate suspicious entries with code paths using URI.join, URI#merge, or URI#+ and with inbound requests that supplied absolute URLs, redirect targets, callback URLs, webhook URLs, import URLs, or next/return parameters. If leakage is suspected, treat the embedded userinfo as compromised, rotate the credentials, and review authentication logs for follow-on use.
- URI.join
- URI#merge
- URI#+
- ://[^/[:space:]]+:[^/@[:space:]]+@
- http://[^/[:space:]]+:[^/@[:space:]]+@
- https://[^/[:space:]]+:[^/@[:space:]]+@
- userinfo
- Gemfile.lock
- uri (1.0.0)
- uri (1.0.1)
- uri (1.0.2)
What your security team should do
- Prioritize upgrade of the uri gem to 1.0.3 or later across Ruby applications, especially services that construct outbound URLs, handle redirects, or integrate with credential-bearing service URLs.
- Search code for URI.join, URI#merge, and URI#+ usage and review whether user-controlled input can change the host of a URL containing userinfo.
- Eliminate credentials embedded in URLs wherever possible and rotate any credentials that may have been exposed through logs, proxies, telemetry, or outbound requests.
- Add automated tests or static checks to prevent userinfo from being retained when URL construction changes hosts.
- Review egress and application logs for historical requests containing userinfo directed to unexpected domains.
- Ensure secret-scanning coverage includes URLs with embedded credentials in logs, traces, error reports, and message queues.
The record
In the URI gem before 1.0.3 for Ruby, the URI handling methods (URI.join, URI#merge, URI#+) have an inadvertent leakage of authentication credentials because userinfo is retained even after changing the host.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| RubyGems | uri | 0 | 0.11.3 |
| RubyGems | uri | 0.12.0 | 0.12.4 |
| RubyGems | uri | 0.13.0 | 0.13.2 |
| RubyGems | uri | 1.0.0 | 1.0.3 |
| AlmaLinux:10 | ruby | 0 | 3.3.8-10.el10_0 |
| AlmaLinux:10 | ruby-bundled-gems | 0 | 3.3.8-10.el10_0 |
| AlmaLinux:10 | ruby-default-gems | 0 | 3.3.8-10.el10_0 |
| AlmaLinux:10 | ruby-devel | 0 | 3.3.8-10.el10_0 |
| AlmaLinux:10 | ruby-doc | 0 | 3.3.8-10.el10_0 |
| AlmaLinux:10 | ruby-libs | 0 | 3.3.8-10.el10_0 |
| AlmaLinux:10 | rubygem-bigdecimal | 0 | 3.1.5-10.el10_0 |
| AlmaLinux:10 | rubygem-bundler | 0 | 2.5.22-10.el10_0 |
| AlmaLinux:10 | rubygem-io-console | 0 | 0.7.1-10.el10_0 |
| AlmaLinux:10 | rubygem-irb | 0 | 1.13.1-10.el10_0 |
| AlmaLinux:10 | rubygem-json | 0 | 2.7.2-10.el10_0 |
| AlmaLinux:10 | rubygem-minitest | 0 | 5.20.0-10.el10_0 |
| AlmaLinux:10 | rubygem-power_assert | 0 | 2.0.3-10.el10_0 |
| AlmaLinux:10 | rubygem-psych | 0 | 5.1.2-10.el10_0 |
| AlmaLinux:10 | rubygem-racc | 0 | 1.7.3-10.el10_0 |
| AlmaLinux:10 | rubygem-rake | 0 | 13.1.0-10.el10_0 |
| AlmaLinux:10 | rubygem-rbs | 0 | 3.4.0-10.el10_0 |
| AlmaLinux:10 | rubygem-rdoc | 0 | 6.6.3.1-10.el10_0 |
| AlmaLinux:10 | rubygem-rexml | 0 | 3.3.9-10.el10_0 |
| AlmaLinux:10 | rubygem-rss | 0 | 0.3.1-10.el10_0 |
| AlmaLinux:10 | rubygem-test-unit | 0 | 3.6.1-10.el10_0 |
| AlmaLinux:10 | rubygem-typeprof | 0 | 0.21.9-10.el10_0 |
| AlmaLinux:10 | rubygems | 0 | 3.5.22-10.el10_0 |
| AlmaLinux:10 | rubygems-devel | 0 | 3.5.22-10.el10_0 |
| AlmaLinux:8 | ruby | 0 | 3.3.8-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | ruby-bundled-gems | 0 | 3.3.8-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | ruby-default-gems | 0 | 3.3.8-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | ruby-devel | 0 | 3.3.8-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | ruby-doc | 0 | 3.3.8-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | ruby-libs | 0 | 3.3.8-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-abrt | 0 | 0.4.0-1.module_el8.10.0+3799+191214cc |
| AlmaLinux:8 | rubygem-abrt-doc | 0 | 0.4.0-1.module_el8.10.0+3799+191214cc |
| AlmaLinux:8 | rubygem-bigdecimal | 0 | 3.1.5-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-bundler | 0 | 2.5.22-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-io-console | 0 | 0.7.1-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-irb | 0 | 1.13.1-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-json | 0 | 2.7.2-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-minitest | 0 | 5.20.0-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-mysql2 | 0 | 0.5.5-1.module_el8.10.0+3799+191214cc |
| AlmaLinux:8 | rubygem-mysql2-doc | 0 | 0.5.5-1.module_el8.10.0+3799+191214cc |
| AlmaLinux:8 | rubygem-pg | 0 | 1.5.4-1.module_el8.10.0+3799+191214cc |
| AlmaLinux:8 | rubygem-pg-doc | 0 | 1.5.4-1.module_el8.10.0+3799+191214cc |
| AlmaLinux:8 | rubygem-power_assert | 0 | 2.0.3-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-psych | 0 | 5.1.2-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-racc | 0 | 1.7.3-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-rake | 0 | 13.1.0-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-rbs | 0 | 3.4.0-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-rdoc | 0 | 6.6.3.1-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-rexml | 0 | 3.3.9-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-rss | 0 | 0.3.1-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-test-unit | 0 | 3.6.1-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygem-typeprof | 0 | 0.21.9-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygems | 0 | 3.5.22-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:8 | rubygems-devel | 0 | 3.5.22-4.module_el8.10.0+4022+8b66723c |
| AlmaLinux:9 | rubygem-mysql2 | 0 | 0.5.4-1.module_el9.1.0+8+503f6fbd |
| AlmaLinux:9 | rubygem-mysql2-doc | 0 | 0.5.4-1.module_el9.1.0+8+503f6fbd |
| AlmaLinux:9 | rubygem-pg | 0 | 1.3.5-1.module_el9.1.0+8+503f6fbd |
| AlmaLinux:9 | rubygem-pg-doc | 0 | 1.3.5-1.module_el9.1.0+8+503f6fbd |
| Chainguard | elasticsearch-8.17 | 0 | 8.17.10-r13 |
| Chainguard | elasticsearch-8.17-config | 0 | 8.17.10-r13 |
| Chainguard | graalvm-23 | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-ce | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-ce-dbg | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-ce-default-jdk | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-ce-jmods | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-ce-nodejs | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-ce-nodejs-dbg | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-ce-nodejs-default-jdk | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-ce-nodejs-jmods | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-graalpy | 0 | 23.0.2-r7 |
| Chainguard | graalvm-23-graalpy-venv | 0 | 23.0.2-r7 |
| Chainguard | jruby-9.4 | 0 | 9.4.14.0-r0 |
| Chainguard | jruby-9.4-default-ruby | 0 | 9.4.14.0-r0 |
| Chainguard | kube-fluentd-operator | 0 | 1.18.2-r33 |
| Chainguard | kube-fluentd-operator-compat | 0 | 1.18.2-r33 |
| Chainguard | kube-fluentd-operator-default-config | 0 | 1.18.2-r33 |
| Chainguard | kube-fluentd-operator-oci-entrypoint | 0 | 1.18.2-r33 |
| Chainguard | logstash-8.17-compat | 0 | 8.17.10-r4 |
| Chainguard | logstash-8.17-env2yaml | 0 | 8.17.10-r4 |
| Chainguard | logstash-8.18-compat | 0 | 8.18.8-r2 |
| Chainguard | logstash-8.18-env2yaml | 0 | 8.18.8-r2 |
| Chainguard | logstash-8.19-compat | 0 | 8.19.6-r0 |
| Chainguard | logstash-8.19-env2yaml | 0 | 8.19.6-r0 |
| Chainguard | logstash-9.0-compat | 0 | 9.0.8-r2 |
| Chainguard | logstash-9.0-env2yaml | 0 | 9.0.8-r2 |
| Chainguard | logstash-9.1-compat | 0 | 9.1.8-r0 |
| Chainguard | logstash-9.1-env2yaml | 0 | 9.1.8-r0 |
| Chainguard | logstash-9.2-compat | 0 | 9.2.0-r0 |
| Chainguard | logstash-9.2-env2yaml | 0 | 9.2.0-r0 |
| Chainguard | ruby-3.1 | 0 | 3.1.6-r12 |
| Chainguard | ruby-3.1-base | 0 | 3.1.6-r12 |
| Chainguard | ruby-3.1-base-dev | 0 | 3.1.6-r12 |
| Chainguard | ruby-3.1-dev | 0 | 3.1.6-r12 |
| Chainguard | ruby-3.1-doc | 0 | 3.1.6-r12 |
| Chainguard | ruby-3.2 | 0 | 3.2.7-r1 |
| Chainguard | ruby-3.2-base | 0 | 3.2.7-r1 |
| Chainguard | ruby-3.2-base-dev | 0 | 3.2.7-r1 |
| Chainguard | ruby-3.2-dev | 0 | 3.2.7-r1 |
| Chainguard | ruby-3.2-doc | 0 | 3.2.7-r1 |
| Chainguard | ruby-3.3 | 0 | 3.3.10-r0 |
| Chainguard | ruby-3.3-dev | 0 | 3.3.10-r0 |
| Chainguard | ruby-3.3-doc | 0 | 3.3.10-r0 |
| Chainguard | ruby-3.4 | 0 | 3.4.2-r1 |
| Chainguard | ruby-3.4-dev | 0 | 3.4.2-r1 |
| Chainguard | ruby-3.4-doc | 0 | 3.4.2-r1 |
| Chainguard | ruby3.2-faraday-1.10.3 | 0 | 1.10.3-r9 |
| Chainguard | ruby3.2-rails-8.0 | 0 | 8.0.1-r3 |
| Chainguard | ruby3.2-rails-8.0-compat | 0 | 8.0.1-r3 |
| Chainguard | ruby3.2-uri | 0 | 1.0.3-r0 |
| Chainguard | ruby3.3-rails-8.0 | 0 | 8.0.2-r1 |
| Chainguard | ruby3.3-rails-8.0-compat | 0 | 8.0.2-r1 |
| Chainguard | ruby3.3-uri | 0 | 1.0.3-r0 |
| Chainguard | ruby3.4-rails-8.0 | 0 | 8.0.2-r1 |
| Chainguard | ruby3.4-rails-8.0-compat | 0 | 8.0.2-r1 |
| Chainguard | ruby3.4-uri | 0 | 1.0.3-r0 |
| Debian:11 | ruby2.7 | 0 | No fix |
| Debian:11 | ruby2.7 | 0 | 2.7.4-1+deb11u5 |
| Debian:11 | rubygems | 0 | No fix |
| Debian:12 | ruby3.1 | 0 | No fix |
| Debian:12 | rubygems | 0 | No fix |
| Debian:13 | ruby3.3 | 0 | No fix |
| Debian:13 | rubygems | 0 | No fix |
| Debian:14 | ruby3.3 | 0 | 3.3.7-2 |
| Debian:14 | rubygems | 0 | 3.6.6-1 |
| Mageia:9 | ruby | 0 | 3.1.5-47.mga9 |
| SUSE:Linux Enterprise Module for Basesystem 15 SP6 | ruby2.5 | 0 | 2.5.9-150000.4.46.1 |
| Wolfi | jruby-9.4 | 0 | 9.4.14.0-r0 |
| Wolfi | jruby-9.4-default-ruby | 0 | 9.4.14.0-r0 |
| Wolfi | kube-fluentd-operator | 0 | 1.18.2-r33 |
| Wolfi | kube-fluentd-operator-compat | 0 | 1.18.2-r33 |
| Wolfi | kube-fluentd-operator-default-config | 0 | 1.18.2-r33 |
| Wolfi | kube-fluentd-operator-oci-entrypoint | 0 | 1.18.2-r33 |
| Wolfi | logstash-9.1-compat | 0 | 9.1.8-r0 |
| Wolfi | logstash-9.1-env2yaml | 0 | 9.1.8-r0 |
| Wolfi | logstash-9.2-compat | 0 | 9.2.0-r0 |
| Wolfi | logstash-9.2-env2yaml | 0 | 9.2.0-r0 |
| Wolfi | ruby-3.1 | 0 | 3.1.6-r12 |
| Wolfi | ruby-3.1-base | 0 | 3.1.6-r12 |
| Wolfi | ruby-3.1-base-dev | 0 | 3.1.6-r12 |
| Wolfi | ruby-3.1-dev | 0 | 3.1.6-r12 |
| Wolfi | ruby-3.1-doc | 0 | 3.1.6-r12 |
| Wolfi | ruby-3.2 | 0 | 3.2.7-r1 |
| Wolfi | ruby-3.2-base | 0 | 3.2.7-r1 |
| Wolfi | ruby-3.2-base-dev | 0 | 3.2.7-r1 |
| Wolfi | ruby-3.2-dev | 0 | 3.2.7-r1 |
| Wolfi | ruby-3.2-doc | 0 | 3.2.7-r1 |
| Wolfi | ruby-3.3 | 0 | 3.3.10-r0 |
| Wolfi | ruby-3.3-dev | 0 | 3.3.10-r0 |
| Wolfi | ruby-3.3-doc | 0 | 3.3.10-r0 |
| Wolfi | ruby-3.4 | 0 | 3.4.2-r1 |
| Wolfi | ruby-3.4-dev | 0 | 3.4.2-r1 |
| Wolfi | ruby-3.4-doc | 0 | 3.4.2-r1 |
| Wolfi | ruby3.2-rails-8.0 | 0 | 8.0.1-r3 |
| Wolfi | ruby3.2-rails-8.0-compat | 0 | 8.0.1-r3 |
| Wolfi | ruby3.2-uri | 0 | 1.0.3-r0 |
| Wolfi | ruby3.3-rails-8.0 | 0 | 8.0.2-r1 |
| Wolfi | ruby3.3-rails-8.0-compat | 0 | 8.0.2-r1 |
| Wolfi | ruby3.3-uri | 0 | 1.0.3-r0 |
| Wolfi | ruby3.4-rails-8.0 | 0 | 8.0.2-r1 |
| Wolfi | ruby3.4-rails-8.0-compat | 0 | 8.0.2-r1 |
| Wolfi | ruby3.4-uri | 0 | 1.0.3-r0 |
| gem | uri | 0.12.0 | 0.12.4 |
| gem | uri | 0.13.0 | 0.13.2 |
| gem | uri | 1.0.0 | 1.0.3 |
| openSUSE:Leap 15.6 | ruby2.5 | 0 | 2.5.9-150000.4.46.1 |
Related vulnerabilities
- CVE-2025-61594 URI is a module providing classes to handle Uniform Resource Identifiers. Also affects uri
- CVE-2025-58767 REXML is an XML toolkit for Ruby. Also affects ruby
- CVE-2025-25186 Net::IMAP implements Internet Message Access Protocol (IMAP) client functionality in Ruby. Also affects ruby
- CVE-2024-49761 REXML is an XML toolkit for Ruby. Also affects ruby
- CVE-2024-41946 REXML is an XML toolkit for Ruby. Also affects ruby
- CVE-2024-41123 REXML is an XML toolkit for Ruby. Also affects ruby
- CVE-2024-39908 REXML is an XML toolkit for Ruby. Also affects ruby
- CVE-2024-27281 An issue was discovered in RDoc 6.3.3 through 6.6.2, as distributed in Ruby 3.x through… Also affects ruby