CVE-2026-53727
css_parser: SSRF and Local File Disclosure in `CssParser::Parser#read_remote_file`
css_parser is a Ruby CSS parser. From 2.2.0 until 3.0.0, CssParser::Parser#read_remote_file in lib/css_parser/parser.rb, and therefore load_uri! and the @import-following branch of add_block!, issued HTTP and HTTPS requests against any host, port, and URI without a scheme allowlist, host or IP filtering, or protection against link-local, loopback, or RFC-1918 addresses. Location: redirects were followed recursively back into the same function, which also serviced file:// URIs, so a single attacker-controlled HTTP redirect could upgrade the bug from SSRF to arbitrary local file disclosure. Any consumer of css_parser that hands it attacker-influenced CSS together with a base_uri: option is exposed. This issue is fixed in version 3.0.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
8.9
css_parser: SSRF and Local File Disclosure in `CssParser::Parser#read_remote_file`
css_parser is a Ruby CSS parser. From 2.2.0 until 3.0.0, CssParser::Parser#read_remote_file in lib/css_parser/parser.rb, and therefore load_uri! and the @import-following branch of add_block!, issued HTTP and HTTPS requests against any host, port, and URI without a scheme allowlist, host or IP filtering, or protection against link-local, loopback, or RFC-1918 addresses. Location: redirects were followed recursively back into the same function, which also serviced file:// URIs, so a single attacker-controlled HTTP redirect could upgrade the bug from SSRF to arbitrary local file disclosure. Any consumer of css_parser that hands it attacker-influenced CSS together with a base_uri: option is exposed. This issue is fixed in version 3.0.0.
- Record
CVE-2026-53727- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Weakness
- CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2026-45324
8.9
css_parser is a Ruby CSS parser. From 2.2.0 until 3.0.0, CssParser::Parser#read_remote_file in lib/css_parser/parser.rb, and therefore load_uri! and the @import-following branch of add_block!, issued HTTP and HTTPS requests against any host, port, and URI without a scheme allowlist, host or IP filtering, or protection against link-local, loopback, or RFC-1918 addresses. Location: redirects were followed recursively back into the same function, which also serviced file:// URIs, so a single attacker-controlled HTTP redirect could upgrade the bug from SSRF to arbitrary local file disclosure. Any consumer of css_parser that hands it attacker-influenced CSS together with a base_uri: option is exposed. This issue is fixed in version 3.0.0.
- Record
EUVD-2026-45324- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-9pmc-p236-855h
8.9
Ruby CSS Parser: SSRF and Local File Disclosure in `CssParser::Parser#read_remote_file`
Summary
CssParser::Parser#read_remote_file (and therefore load_uri!, and the @import-following branch of add_block!) issues HTTP/HTTPS requests against any host, port and URI it is handed, with no scheme allowlist, no host / IP filtering, and no protection against link-local, loopback or RFC‑1918 addresses. Location: redirects are followed recursively back into the same function, which also services file:// URIs, so a single attacker-controlled HTTP redirect upgrades the bug from SSRF to arbitrary local file disclosure.
In practice, any consumer of css_parser that hands it attacker‑influenced CSS together with a base_uri: option — Premailer being the canonical example — is exposed. The attacker only needs the ability to land one @import url(...) in the CSS that the host application parses.
Vulnerable code
lib/css_parser/parser.rb#L613-L687:
def read_remote_file(uri) # :nodoc:
...
begin
uri = Addressable::URI.parse(uri.to_s)
if uri.scheme == 'file'
# local file
path = uri.path
path.gsub!(%r{^/}, '') if Gem.win_platform?
src = File.read(path, mode: 'rb') # <-- arbitrary local read
else
# remote file
if uri.scheme == 'https'
uri.port = 443 unless uri.port
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
else
http = Net::HTTP.new(uri.host, uri.port) # <-- arbitrary host:port
end
res = http.get(uri.request_uri, ...)
...
elsif res.code.to_i >= 300 and res.code.to_i < 400
unless res['Location'].nil?
return read_remote_file Addressable::URI.parse(...) # <-- cross-scheme redirect
end
end
...
There is no validation of uri.host, uri.scheme, or the resolved IP address — neither before the HTTP request, nor before the recursive call on the Location header.
The user-facing entry points that reach this sink are:
Parser#load_uri!— directly callsread_remote_file(line 513).Parser#add_block!— when invoked withbase_uri:and the defaultimport: true, scans the CSS for@import url(...)rules and resolves each one throughload_uri!(line 150).
Threat model and scope
| Capability | Reachable? | Notes |
|---|---|---|
| Arbitrary outbound http:// / https:// GET to any host:port reachable from the server | ✅ | No host, IP, port or scheme allowlist. Works against loopback, RFC‑1918, link‑local (169.254/16, AWS / GCP / Azure IMDS), and Docker / k8s service IPs. |
| Recovering the response body | ✅ (conditional) | The body is fed back into add_block!. Any bytes that form selector { decl } round‑trip out via Parser#each_selector / to_s. A consumer that emits the parsed CSS (e.g. Premailer inlining into HTML) leaks the body to the original attacker. |
| Local file read via cross-scheme redirect (Location: file://...) | ⚠️ partial | Redirect is followed without checking the new scheme; the recursive call services file:// with File.read. The read itself executes against any path the Ruby process can open. Content recovery via the parser API is constrained by CSS grammar — see "File-disclosure scope" below. |
| File-existence oracle | ✅ | With default io_exceptions: true, missing paths raise CssParser::RemoteFileError and existing paths return silently. An attacker can iterate file:// targets to enumerate filesystem layout, usernames, installed software, etc. |
| Side-effecting GETs against unprotected internal admin endpoints | ✅ | Even with a non‑CSS response, the request…
- Record
GHSA-9pmc-p236-855h- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Weakness
- CWE-918
- Updated
- 2026-11-02
NVD
8.9
css_parser is a Ruby CSS parser. From 2.2.0 until 3.0.0, CssParser::Parser#read_remote_file in lib/css_parser/parser.rb, and therefore load_uri! and the @import-following branch of add_block!, issued HTTP and HTTPS requests against any host, port, and URI without a scheme allowlist, host or IP filtering, or protection against link-local, loopback, or RFC-1918 addresses. Location: redirects were followed recursively back into the same function, which also serviced file:// URIs, so a single attacker-controlled HTTP redirect could upgrade the bug from SSRF to arbitrary local file disclosure. Any consumer of css_parser that hands it attacker-influenced CSS together with a base_uri: option is exposed. This issue is fixed in version 3.0.0.
- Record
CVE-2026-53727- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSV
8.9
css_parser: SSRF and Local File Disclosure in `CssParser::Parser#read_remote_file`
css_parser is a Ruby CSS parser. From 2.2.0 until 3.0.0, CssParser::Parser#read_remote_file in lib/css_parser/parser.rb, and therefore load_uri! and the @import-following branch of add_block!, issued HTTP and HTTPS requests against any host, port, and URI without a scheme allowlist, host or IP filtering, or protection against link-local, loopback, or RFC-1918 addresses. Location: redirects were followed recursively back into the same function, which also serviced file:// URIs, so a single attacker-controlled HTTP redirect could upgrade the bug from SSRF to arbitrary local file disclosure. Any consumer of css_parser that hands it attacker-influenced CSS together with a base_uri: option is exposed. This issue is fixed in version 3.0.0.
- Record
CVE-2026-53727- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-53727
8.6
css_parser is a Ruby CSS parser. From 2.2.0 until 3.0.0, CssParser::Parser#read_remote_file in lib/css_parser/parser.rb, and therefore load_uri! and the @import-following branch of add_block!, issued HTTP and HTTPS requests against any host, port, and URI without a scheme allowlist, host or IP filtering, or protection against link-local, loopback, or RFC-1918 addresses. Location: redirects were followed recursively back into the same function, which also serviced file:// URIs, so a single attacker-controlled HTTP redirect could upgrade the bug from SSRF to arbitrary local file disclosure. Any consumer of css_parser that hands it attacker-influenced CSS together with a base_uri: option is exposed. This issue is fixed in version 3.0.0.
- Record
DEBIAN-CVE-2026-53727- CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Updated
- 2026-11-02
OSVGHSA-9pmc-p236-855h
8.9
Ruby CSS Parser: SSRF and Local File Disclosure in `CssParser::Parser#read_remote_file`
Summary
CssParser::Parser#read_remote_file (and therefore load_uri!, and the @import-following branch of add_block!) issues HTTP/HTTPS requests against any host, port and URI it is handed, with no scheme allowlist, no host / IP filtering, and no protection against link-local, loopback or RFC‑1918 addresses. Location: redirects are followed recursively back into the same function, which also services file:// URIs, so a single attacker-controlled HTTP redirect upgrades the bug from SSRF to arbitrary local file disclosure.
In practice, any consumer of css_parser that hands it attacker‑influenced CSS together with a base_uri: option — Premailer being the canonical example — is exposed. The attacker only needs the ability to land one @import url(...) in the CSS that the host application parses.
Vulnerable code
lib/css_parser/parser.rb#L613-L687:
def read_remote_file(uri) # :nodoc:
...
begin
uri = Addressable::URI.parse(uri.to_s)
if uri.scheme == 'file'
# local file
path = uri.path
path.gsub!(%r{^/}, '') if Gem.win_platform?
src = File.read(path, mode: 'rb') # <-- arbitrary local read
else
# remote file
if uri.scheme == 'https'
uri.port = 443 unless uri.port
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
else
http = Net::HTTP.new(uri.host, uri.port) # <-- arbitrary host:port
end
res = http.get(uri.request_uri, ...)
...
elsif res.code.to_i >= 300 and res.code.to_i < 400
unless res['Location'].nil?
return read_remote_file Addressable::URI.parse(...) # <-- cross-scheme redirect
end
end
...
There is no validation of uri.host, uri.scheme, or the resolved IP address — neither before the HTTP request, nor before the recursive call on the Location header.
The user-facing entry points that reach this sink are:
Parser#load_uri!— directly callsread_remote_file(line 513).Parser#add_block!— when invoked withbase_uri:and the defaultimport: true, scans the CSS for@import url(...)rules and resolves each one throughload_uri!(line 150).
Threat model and scope
| Capability | Reachable? | Notes |
|---|---|---|
| Arbitrary outbound http:// / https:// GET to any host:port reachable from the server | ✅ | No host, IP, port or scheme allowlist. Works against loopback, RFC‑1918, link‑local (169.254/16, AWS / GCP / Azure IMDS), and Docker / k8s service IPs. |
| Recovering the response body | ✅ (conditional) | The body is fed back into add_block!. Any bytes that form selector { decl } round‑trip out via Parser#each_selector / to_s. A consumer that emits the parsed CSS (e.g. Premailer inlining into HTML) leaks the body to the original attacker. |
| Local file read via cross-scheme redirect (Location: file://...) | ⚠️ partial | Redirect is followed without checking the new scheme; the recursive call services file:// with File.read. The read itself executes against any path the Ruby process can open. Content recovery via the parser API is constrained by CSS grammar — see "File-disclosure scope" below. |
| File-existence oracle | ✅ | With default io_exceptions: true, missing paths raise CssParser::RemoteFileError and existing paths return silently. An attacker can iterate file:// targets to enumerate filesystem layout, usernames, installed software, etc. |
| Side-effecting GETs against unprotected internal admin endpoints | ✅ | Even with a non‑CSS response, the request…
- Record
GHSA-9pmc-p236-855h- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-53727
8.9
css_parser is a Ruby CSS parser. From 2.2.0 until 3.0.0, CssParser::Parser#read_remote_file in lib/css_parser/parser.rb, and therefore load_uri! and the @import-following branch of add_block!, issued HTTP and HTTPS requests against any host, port, and URI without a scheme allowlist, host or IP filtering, or protection against link-local, loopback, or RFC-1918 addresses. Location: redirects were followed recursively back into the same function, which also serviced file:// URIs, so a single attacker-controlled HTTP redirect could upgrade the bug from SSRF to arbitrary local file disclosure. Any consumer of css_parser that hands it attacker-influenced CSS together with a base_uri: option is exposed. This issue is fixed in version 3.0.0.
- Record
UBUNTU-CVE-2026-53727- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
css_parserRubyGems |
before 3.0.0 | 3.0.0 |
ruby-css-parserDebian:12 |
All versions, plus listed versions 1.16.0-11.19.0-11.21.1-11.6.0-21.6.0-2+deb12u1 Show 5 moreShow less2.0.0-12.1.0-13.0.0-13.1.0-13.3.0-1 |
None known |
ruby-css-parserDebian:13 |
All versions, plus listed versions 1.19.0-11.19.0-1+deb13u11.21.1-12.0.0-12.1.0-13.0.0-13.1.0-13.3.0-1 |
None known |
ruby-css-parserDebian:14 |
before 3.0.0-1, plus listed versions 1.19.0-11.21.1-12.0.0-12.1.0-1 |
3.0.0-1 |
css_parserRubyGems |
before 3.0.0, plus listed versions 0.9.00.9.11.0.01.0.11.1.1 Show 45 moreShow less1.1.21.1.31.1.41.1.51.1.61.1.71.1.81.1.91.10.01.11.01.12.01.13.01.14.01.15.01.16.01.17.01.17.11.19.01.19.11.2.11.2.21.2.31.2.41.2.51.2.61.20.01.21.01.21.11.22.01.3.01.3.11.3.21.3.31.3.41.3.51.3.61.3.71.4.01.4.11.4.101.4.21.4.31.4.41.4.51.4.6 |
3.0.0 |
ruby-css-parserUbuntu:16.04:LTS |
All versions, plus listed versions 1.3.6-1 |
None known |
ruby-css-parserUbuntu:18.04:LTS |
All versions, plus listed versions 1.3.6-11.6.0-1 |
None known |
ruby-css-parserUbuntu:20.04:LTS |
All versions, plus listed versions 1.6.0-1 |
None known |
ruby-css-parserUbuntu:22.04:LTS |
All versions, plus listed versions 1.6.0-11.6.0-2 |
None known |
ruby-css-parserUbuntu:24.04:LTS |
All versions, plus listed versions 1.6.0-21.16.0-1 |
None known |
ruby-css-parserUbuntu:26.10 |
All versions, plus listed versions 1.21.1-12.1.0-13.0.0-1 |
None known |
ruby-css-parserUbuntu:26.04:LTS |
All versions, plus listed versions 1.19.0-11.21.1-1 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-53727 is a high vulnerability (CVSS 8.9) in Premailer Css Parser, published July 9, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.51%, the 43rd percentile. Fixed in css_parser 3.0.0.
References
github.com/premailer/css_parser/security/advisories/GHSA-9pmc-p236-855h
github.com/premailer/css_parser/commit/7d2ddf0189cd54b54f378f59daefa10cb036e476
github.com/premailer/css_parser/commit/e0a151458b2a801ae265ba420862ef8b1127b3ae
github.com/premailer/css_parser/releases/tag/v3.0.0
github.com/rubysec/ruby-advisory-db/blob/master/gems/css_parser/CVE-2026-53727.yml
cve.org/CVERecord/SearchResults?query=CVE-2026-53727
Show 7 moreShow less
github.com/advisories/GHSA-9pmc-p236-855h
github.com/CVEProject/cvelistV5/tree/main/cves/2026/53xxx/CVE-2026-53727.json
nvd.nist.gov/vuln/detail/CVE-2026-53727
security-tracker.debian.org/tracker/CVE-2026-53727
github.com/premailer/css_parser
ubuntu.com/security/CVE-2026-53727
cve.org/CVERecord?id=CVE-2026-53727
Left out here: 14 versions and the rest of 2 source descriptions. The JSON record has them.