css_parser 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/css_parser/parser.rb +48 -1
- data/lib/css_parser/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b1b890ee0d537d338ae0a218c68424271242859ba814a52c27fcd05ffefe1acd
|
|
4
|
+
data.tar.gz: 147e41dae4da802d96124fc07b488b122967a44c0ff79bfe623291c1795e0d9b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 76728b4b816f4b620f28198b6fd5f92f005733bec3afba0df5707d8daf99ab650fd0a0143a6222fc53c5453c32c3a13a76eb4877f3c06f5dc903a559a18d200f
|
|
7
|
+
data.tar.gz: a5b5a901312932dd9d3c50fa9a6cd4ea549180f57a7e4d85d700d5c3ec58f458927be66c2eb7169165333e153d58061dbdfa98c75c0e6ffb6a81181bc78fdd6f
|
data/lib/css_parser/parser.rb
CHANGED
|
@@ -173,6 +173,21 @@ module CssParser
|
|
|
173
173
|
load_uri!(import_uri, import_options)
|
|
174
174
|
elsif options[:base_dir]
|
|
175
175
|
import_options[:base_dir] = options[:base_dir]
|
|
176
|
+
# The import path comes from (potentially untrusted) CSS
|
|
177
|
+
# content, not from the caller. Flag this load so load_file!
|
|
178
|
+
# keeps it contained within the import root and refuses
|
|
179
|
+
# absolute paths / `..` traversal that escape it -- otherwise
|
|
180
|
+
# @import turns into arbitrary local file disclosure. This is
|
|
181
|
+
# the base_dir sibling of the file://-via-base_uri hole closed
|
|
182
|
+
# in GHSA-9pmc-p236-855h, which left this arm untouched.
|
|
183
|
+
#
|
|
184
|
+
# import_root is the top-level base_dir, threaded through
|
|
185
|
+
# nested imports so containment is always checked against it.
|
|
186
|
+
# That still allows legitimate `../` imports that stay inside
|
|
187
|
+
# the tree (e.g. subdir/import2.css -> ../simple.css) while
|
|
188
|
+
# rejecting anything that leaves it.
|
|
189
|
+
import_options[:from_import] = true
|
|
190
|
+
import_options[:import_root] = options[:import_root] || options[:base_dir]
|
|
176
191
|
load_file!(import_path, import_options)
|
|
177
192
|
end
|
|
178
193
|
end
|
|
@@ -558,8 +573,18 @@ module CssParser
|
|
|
558
573
|
end
|
|
559
574
|
|
|
560
575
|
# Load a local CSS file.
|
|
576
|
+
#
|
|
577
|
+
# +from_import+ (internal) marks a load whose +file_name+ originates
|
|
578
|
+
# from an @import rule in parsed CSS rather than from the caller. Such
|
|
579
|
+
# a path is attacker-influenced, so it is contained within the import
|
|
580
|
+
# root (+import_root+, the top-level +base_dir+): absolute paths and
|
|
581
|
+
# `..` traversal that escape the root are refused (raising
|
|
582
|
+
# RemoteFileError when io_exceptions are on, otherwise a silent no-op).
|
|
583
|
+
# Direct callers (the default, +from_import: false+) are unaffected --
|
|
584
|
+
# load_file! remains the explicit, trusted local-file API and may load
|
|
585
|
+
# any readable path.
|
|
561
586
|
def load_file!(file_name, options = {}, deprecated = nil)
|
|
562
|
-
opts = {base_dir: nil, media_types: :all}
|
|
587
|
+
opts = {base_dir: nil, media_types: :all, from_import: false, import_root: nil}
|
|
563
588
|
|
|
564
589
|
if options.is_a? Hash
|
|
565
590
|
opts.merge!(options)
|
|
@@ -570,7 +595,29 @@ module CssParser
|
|
|
570
595
|
opts[:media_types] = deprecated if deprecated
|
|
571
596
|
end
|
|
572
597
|
|
|
598
|
+
# Pin the containment root to the first base_dir seen in the chain.
|
|
599
|
+
# load_file! resets base_dir to each file's own directory as it
|
|
600
|
+
# recurses, so without this a file loaded from a subdirectory would
|
|
601
|
+
# shrink the sandbox and reject a legitimate `..` back toward the
|
|
602
|
+
# caller's original base_dir.
|
|
603
|
+
opts[:import_root] ||= opts[:base_dir]
|
|
604
|
+
|
|
573
605
|
file_name = File.expand_path(file_name, opts[:base_dir])
|
|
606
|
+
|
|
607
|
+
# Containment check for @import-sourced paths: the resolved file must
|
|
608
|
+
# stay inside the import root. Rejects both `@import "/etc/passwd"`
|
|
609
|
+
# (absolute) and `@import "../../secret"` (traversal escaping the
|
|
610
|
+
# tree) from untrusted CSS, while leaving direct load_file! callers
|
|
611
|
+
# untouched and still permitting `..` that stays within the root.
|
|
612
|
+
if opts[:from_import] && (opts[:import_root] || opts[:base_dir])
|
|
613
|
+
root = File.expand_path((opts[:import_root] || opts[:base_dir]).to_s)
|
|
614
|
+
unless file_name == root || file_name.start_with?(root + File::SEPARATOR)
|
|
615
|
+
raise RemoteFileError, file_name if @options[:io_exceptions]
|
|
616
|
+
|
|
617
|
+
return
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
574
621
|
return unless File.readable?(file_name)
|
|
575
622
|
return unless circular_reference_check(file_name)
|
|
576
623
|
|
data/lib/css_parser/version.rb
CHANGED