### Description `Symfony\Component\Routing\Generator\UrlGenerator::doGenerate()` percent-encodes `.` and `..` path segments so that the generated URL still resolves to the originating route after RFC 3986 §5.2.4 dot-segment removal (which strict RFC-3986 consumers — routers, reverse proxies, HTTP clients — perform *before* percent-decoding). The encoding was implemented as `strtr($url, ['/../' => '/%2E%2E/', '/./' => '/%2E/'])` plus a trailing-segment fixup. `strtr` advances past the trailing `/` of each match, so the next dot-segment in a chained sequence was left unescaped: | Input | Output (before fix) | Expected | | -------------------- | ---------------------------------------- | ----------------------------------- | | `/../../../` | `/%2E%2E/../%2E%2E/` | `/%2E%2E/%2E%2E/%2E%2E/` | | `/foo/../../../bar` | `/foo/%2E%2E/../%2E%2E/bar` | `/foo/%2E%2E/%2E%2E/%2E%2E/bar` | When a route exposes a parameter constrained by a permissive requirement (`.+`, `.*`, or similar) that accepts dots and slashes, attacker-controlled chained `..` or `.` segments produce a generated URL that, under strict RFC 3986 normalization, collapses to a different path than the originating route. The Twig `path()` / `url()` helpers and any server-side use of `UrlGenerator` are affected. Same class of route round-trip integrity issue as CVE-2026-45065. Note: WHATWG-conformant browsers treat `%2E`/`%2E%2E` as dot-segments during URL parsing, so the encoding never protected browser-side traversal. The defense exists for RFC-3986-conformant consumers; restoring it for chained segments closes the gap there. ### Resolution `UrlGenerator` now matches every `/.` or `/..` dot-segment in a single left-to-right `preg_replace_callback` pass using a lookahead that does not consume the trailing `/`, so adjacent dot-segments are encoded correctly. The patches for this issue are available [here](https://github.com/symfony/symfony/commit/4b63c3a3f7af04ecd79c89a594b0b02a01990b1d) for branch 5.4 (and forward-ported to 6.4, 7.4, 8.0 and 8.1). ### Credits Symfony would like to thank Alex Pott for reporting the issue and Nicolas Grekas for providing the fix.
### Description `Symfony\Component\Routing\Generator\UrlGenerator::doGenerate()` percent-encodes `.` and `..` path segments so that the generated URL still resolves to the originating route after RFC 3986 §5.2.4 dot-segment removal (which strict RFC-3986 consumers — routers, reverse proxies, HTTP clients — perform *before* percent-decoding). The encoding was implemented as `strtr($url, ['/../' => '/%2E%2E/', '/./' => '/%2E/'])` plus a trailing-segment fixup. `strtr` advances past the trailing `/` of each match, so the next dot-segment in a chained sequence was left unescaped: | Input | Output (before fix) | Expected | | -------------------- | ---------------------------------------- | ----------------------------------- | | `/../../../` | `/%2E%2E/../%2E%2E/` | `/%2E%2E/%2E%2E/%2E%2E/` | | `/foo/../../../bar` | `/foo/%2E%2E/../%2E%2E/bar` | `/foo/%2E%2E/%2E%2E/%2E%2E/bar` | When a route exposes a parameter constrained by a permissive requirement (`.+`, `.*`, or similar) that accepts dots and slashes, attacker-controlled chained `..` or `.` segments produce a generated URL that, under strict RFC 3986 normalization, collapses to a different path than the originating route. The Twig `path()` / `url()` helpers and any server-side use of `UrlGenerator` are affected. Same class of route round-trip integrity issue as CVE-2026-45065. Note: WHATWG-conformant browsers treat `%2E`/`%2E%2E` as dot-segments during URL parsing, so the encoding never protected browser-side traversal. The defense exists for RFC-3986-conformant consumers; restoring it for chained segments closes the gap there. ### Resolution `UrlGenerator` now matches every `/.` or `/..` dot-segment in a single left-to-right `preg_replace_callback` pass using a lookahead that does not consume the trailing `/`, so adjacent dot-segments are encoded correctly. The patches for this issue are available [here](https://github.com/symfony/symfony/commit/4b63c3a3f7af04ecd79c89a594b0b02a01990b1d) for branch 5.4 (and forward-ported to 6.4, 7.4, 8.0 and 8.1). ### Credits Symfony would like to thank Alex Pott for reporting the issue and Nicolas Grekas for providing the fix.
Update symfony/routing to 7.4.13; symfony/routing to 8.0.13; symfony/routing to 5.4.53; symfony/routing to 6.4.41; symfony/symfony to 5.4.53; symfony/symfony to 6.4.41; symfony/symfony to 7.4.13; symfony/symfony to 8.0.13 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanSymfony: UrlGenerator Dot-Segment Encoding Skips Every Other Chained `../` or `./` → Generated URL Collapses Off-Route Under RFC 3986 Normalization affects symfony/routing (composer), symfony/routing (composer), symfony/routing (composer), symfony/routing (composer), symfony/symfony (composer), symfony/symfony (composer), symfony/symfony (composer), symfony/symfony (composer). Severity is medium. ### Description `Symfony\Component\Routing\Generator\UrlGenerator::doGenerate()` percent-encodes `.` and `..` path segments so that the generated URL still resolves to the originating route after RFC 3986 §5.2.4 dot-segment removal (which strict RFC-3986 consumers — routers, reverse proxies, HTTP clients — perform *before* percent-decoding). The encoding was implemented as `strtr($url, ['/../' => '/%2E%2E/', '/./' => '/%2E/'])` plus a trailing-segment fixup. `strtr` advances past the trailing `/` of each match, so the next dot-segment in a chained sequence was left unescaped: | Input | Output (before fix) | Expected | | -------------------- | ---------------------------------------- | ----------------------------------- | | `/../../../` | `/%2E%2E/../%2E%2E/` | `/%2E%2E/%2E%2E/%2E%2E/` | | `/foo/../../../bar` | `/foo/%2E%2E/../%2E%2E/bar` | `/foo/%2E%2E/%2E%2E/%2E%2E/bar` | When a route exposes a parameter constrained by a permissive requirement (`.+`, `.*`, or similar) that accepts dots and slashes, attacker-controlled chained `..` or `.` segments produce a generated URL that, under strict RFC 3986 normalization, collapses to a different path than the originating route. The Twig `path()` / `url()` helpers and any server-side use of `UrlGenerator` are affected. Same class of route round-trip integrity issue as CVE-2026-45065. Note: WHATWG-conformant browsers treat `%2E`/`%2E%2E` as dot-segments during URL parsing, so the encoding never protected browser-side traversal. The defense exists for RFC-3986-conformant consumers; restoring it for chained segments closes the gap there. ### Resolution `UrlGenerator` now matches every `/.` or `/..` dot-segment in a single left-to-right `preg_replace_callback` pass using a lookahead that does not consume the trailing `/`, so adjacent dot-segments are encoded correctly. The patches for this issue are available [here](https://github.com/symfony/symfony/commit/4b63c3a3f7af04ecd79c89a594b0b02a01990b1d) for branch 5.4 (and forward-ported to 6.4, 7.4, 8.0 and 8.1). ### Credits Symfony would like to thank Alex Pott for reporting the issue and Nicolas Grekas for providing the fix.
AI coding agents often install or upgrade packages automatically in composer. A medium vulnerability in a dependency can be pulled into a project through a normal install or update without a human reviewing the change, expanding the blast radius from a single package to every agent workspace that depends on it.
| Package | Affected range | Fixed version |
|---|---|---|
| symfony/routingcomposer | >=7.0.0,<7.4.13 | 7.4.13 |
| symfony/routingcomposer | >=8.0.0,<8.0.13 | 8.0.13 |
| symfony/routingcomposer | <5.4.53 | 5.4.53 |
| symfony/routingcomposer | >=6.0.0,<6.4.41 | 6.4.41 |
| symfony/symfonycomposer | <5.4.53 | 5.4.53 |
| symfony/symfonycomposer | >=6.0.0,<6.4.41 | 6.4.41 |
| symfony/symfonycomposer | >=7.0.0,<7.4.13 | 7.4.13 |
Reported by GitHub Security Advisories (ghsa).
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL GuardUpdate symfony/routing to 7.4.13; symfony/routing to 8.0.13; symfony/routing to 5.4.53; symfony/routing to 6.4.41; symfony/symfony to 5.4.53; symfony/symfony to 6.4.41; symfony/symfony to 7.4.13; symfony/symfony to 8.0.13 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanSymfony: UrlGenerator Dot-Segment Encoding Skips Every Other Chained `../` or `./` → Generated URL Collapses Off-Route Under RFC 3986 Normalization affects symfony/routing (composer), symfony/routing (composer), symfony/routing (composer), symfony/routing (composer), symfony/symfony (composer), symfony/symfony (composer), symfony/symfony (composer), symfony/symfony (composer). Severity is medium. ### Description `Symfony\Component\Routing\Generator\UrlGenerator::doGenerate()` percent-encodes `.` and `..` path segments so that the generated URL still resolves to the originating route after RFC 3986 §5.2.4 dot-segment removal (which strict RFC-3986 consumers — routers, reverse proxies, HTTP clients — perform *before* percent-decoding). The encoding was implemented as `strtr($url, ['/../' => '/%2E%2E/', '/./' => '/%2E/'])` plus a trailing-segment fixup. `strtr` advances past the trailing `/` of each match, so the next dot-segment in a chained sequence was left unescaped: | Input | Output (before fix) | Expected | | -------------------- | ---------------------------------------- | ----------------------------------- | | `/../../../` | `/%2E%2E/../%2E%2E/` | `/%2E%2E/%2E%2E/%2E%2E/` | | `/foo/../../../bar` | `/foo/%2E%2E/../%2E%2E/bar` | `/foo/%2E%2E/%2E%2E/%2E%2E/bar` | When a route exposes a parameter constrained by a permissive requirement (`.+`, `.*`, or similar) that accepts dots and slashes, attacker-controlled chained `..` or `.` segments produce a generated URL that, under strict RFC 3986 normalization, collapses to a different path than the originating route. The Twig `path()` / `url()` helpers and any server-side use of `UrlGenerator` are affected. Same class of route round-trip integrity issue as CVE-2026-45065. Note: WHATWG-conformant browsers treat `%2E`/`%2E%2E` as dot-segments during URL parsing, so the encoding never protected browser-side traversal. The defense exists for RFC-3986-conformant consumers; restoring it for chained segments closes the gap there. ### Resolution `UrlGenerator` now matches every `/.` or `/..` dot-segment in a single left-to-right `preg_replace_callback` pass using a lookahead that does not consume the trailing `/`, so adjacent dot-segments are encoded correctly. The patches for this issue are available [here](https://github.com/symfony/symfony/commit/4b63c3a3f7af04ecd79c89a594b0b02a01990b1d) for branch 5.4 (and forward-ported to 6.4, 7.4, 8.0 and 8.1). ### Credits Symfony would like to thank Alex Pott for reporting the issue and Nicolas Grekas for providing the fix.
AI coding agents often install or upgrade packages automatically in composer. A medium vulnerability in a dependency can be pulled into a project through a normal install or update without a human reviewing the change, expanding the blast radius from a single package to every agent workspace that depends on it.
| Package | Affected range | Fixed version |
|---|---|---|
| symfony/routingcomposer | >=7.0.0,<7.4.13 | 7.4.13 |
| symfony/routingcomposer | >=8.0.0,<8.0.13 | 8.0.13 |
| symfony/routingcomposer | <5.4.53 | 5.4.53 |
| symfony/routingcomposer | >=6.0.0,<6.4.41 | 6.4.41 |
| symfony/symfonycomposer | <5.4.53 | 5.4.53 |
| symfony/symfonycomposer | >=6.0.0,<6.4.41 | 6.4.41 |
| symfony/symfonycomposer | >=7.0.0,<7.4.13 | 7.4.13 |
Reported by GitHub Security Advisories (ghsa).
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL Guard| symfony/symfonycomposer | >=8.0.0,<8.0.13 | 8.0.13 |
|---|
Fixed versions are reported by the source feed; confirm compatibility before updating.
| symfony/symfonycomposer | >=8.0.0,<8.0.13 | 8.0.13 |
|---|
Fixed versions are reported by the source feed; confirm compatibility before updating.