Skip to main content
Press slash or control plus K to focus the search. Use the arrow keys to navigate results and press enter to open a threat.
Reconnecting to live updates…

GHSA-9pmc-p236-855h: Ruby CSS Parser: SSRF and Local File Disclosure in `CssParser::Parser#read_remote_file`

0
High
Published: 07/09/2026 (07/09/2026, 13:43:13 UTC)
Source: GCVE Database
Product: css_parser

Description

## 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`](https://github.com/premailer/css_parser/blob/cee10f16b11dd175f17b0e5f6aefa488378e964b/lib/css_parser/parser.rb#L613-L687): ```ruby 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!`](https://github.com/premailer/css_parser/blob/cee10f16b11dd175f17b0e5f6aefa488378e964b/lib/css_parser/parser.rb#L489-L516) — directly calls `read_remote_file` (line 513). - [`Parser#add_block!`](https://github.com/premailer/css_parser/blob/cee10f16b11dd175f17b0e5f6aefa488378e964b/lib/css_parser/parser.rb#L117-L162) — when invoked with `base_uri:` and the default `import: true`, scans the CSS for `@import url(...)` rules and resolves each one through `load_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 still fires. Internal services that act on GET (legacy admin panels, debug endpoints, cache busters, queue triggers) execute. | | Forced gzip / deflate decompression (DoS / decompression bomb) | ✅ | `Accept-Encoding: gzip` is hardcoded (line 650) and the body is decompressed with `Zlib::GzipReader` / `Zlib::Inflate` (lines 665-672). An attacker server can return a small gzipped payload that decompresses to multiple GB. | | HTTPS internal targets with self-signed / private CA certs | ⚠️ | `Net::HTTP#use_ssl = true` defaults to `VERIFY_PEER`, so internal HTTPS hosts with private certs will fail the SSL handshake. Plain HTTP, and HTTPS hosts whose certs chain to a CA trusted by the process, are fully exploitable. | | Smuggling other TCP protocols (Redis, Memcached, etc.) via the HTTP client | ⚠️ | `Net::HTTP` writes a real HTTP request line, so Redis / Memcached won't accept it. The TCP connect itself does occur, which can still trigger logs, port-scan effects, and connection-state side effects in firewalled environments. |

CVSS v4.0

Attack Vector
Network
Attack Complexity
Low
Attack Requirements
Present
Privileges Required
None
User Interaction
None
Vuln. Confidentiality
High
Vuln. Integrity
None
Vuln. Availability
None
Subsq. Confidentiality
High
Subsq. Integrity
None
Subsq. Availability
None
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

Affected software

RubyGemsghsa
css_parser
Affected versions
<3.0.0

Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.

Technical Details

Gcve Source
db.gcve.eu
Osv Id
GHSA-9pmc-p236-855h
Osv Schema Version
1.4.0
Aliases
["CVE-2026-53727"]
Ecosystems
["RubyGems"]
Database Specific Severity
HIGH
Cvss Version
4.0

Threat ID: 6a50bac868715ace435892a4

Added to database: 07/10/2026, 09:26:32 UTC

Last updated: 07/10/2026, 09:26:32 UTC

Views: 1

Community Reviews

0 reviews

Crowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.

Sort by
Loading community insights…

Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.

Actions

Please log in to the Console to use AI analysis features.

Need more coverage?

Upgrade to Pro Console for AI refresh and higher limits.

For incident response and remediation, OffSeq services can help resolve threats faster.

Latest Threats

Breach by OffSeqOFFSEQFRIENDS — 25% OFF

Check if your credentials are on the dark web

Instant breach scanning across billions of leaked records. Free tier available.

Scan now
OffSeq TrainingCredly Certified

Lead Pen Test Professional

Technical5-day eLearningPECB Accredited
View courses