Update dependency postcss to v8.5.18 [SECURITY]#190
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
8.5.16→8.5.18PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) leads to Arbitrary .map File Disclosure
GHSA-r28c-9q8g-f849
More information
Details
Vulnerability Details
File:
lib/previous-map.jsLine: 87-98 (
loadFile), 129-144 (loadMap)Root Cause
PostCSS auto-detects a
/*# sourceMappingURL=... */comment inside the CSS text it is asked to parse and, unless the caller explicitly passesmap: false, attempts to load that path from disk as a "previous source map." This happens on everypostcss.parse()/postcss().process()call by default (opt-out, not opt-in).loadMap()builds the candidate path viajoin(dirname(opts.from), annotation), whereannotationis the raw, attacker-controlled string from the CSS comment.path.join()normalizes but does not sandbox..segments, so a../../../prefix walks the resolved path outside the intended directory. Ifopts.fromis not set at all, the annotation is used completely unmodified — an absolute path in the CSS comment is read verbatim.8.5.12 already fixed a strictly worse variant of this (any file, any extension, could be read) by requiring the resolved path to end in
.map(loadFile()). That fix did not address the traversal itself, only the target extension. Since thejoin(dirname(file), map)logic has existed unchanged since PostCSS 8.0.0 (Feb 2020), any file ending in.mapremains readable through this path in the current release (8.5.16).Once loaded,
MapGenerator.isMap()treats the mere presence of a loaded "previous map" as an implicit request to generateresult.map, even when the caller never set themapoption. If the loaded map has asourcesContentfield (common for maps emitted by bundlers/transpilers), that content is merged intoresult.mapand returned to the caller — disclosing the traversed-to file's content to whoever supplied the CSS.Attack Scenario
postcss().process(userCss, { from: '/app/uploads/user123/input.css', to: '/app/uploads/user123/output.css' })— idiomatic usage;mapoption untouched./*# sourceMappingURL=../../../../some/other/app/dist/bundle.js.map */(or an absolute path iffromis unset)..mapfile and folds itssourcesContentintoresult.map.result.map— writes it next to the CSS output or returns it via API (source maps are meant to be consumed by browser devtools, so this is commonly public/served).Impact
Disclosure of the contents of arbitrary
.mapfiles reachable via path traversal (or absolute path whenfromis unset) from the process's filesystem. Affects any application processing CSS it does not fully trust without explicitly passingmap: false. No authentication or user interaction beyond submitting CSS text is required.Vulnerable Code
Recommended Fix
Constrain the resolved path to remain inside the CSS file's own directory instead of relying solely on a filename-extension check:
I've implemented, tested (full existing test suite — 660/660 passing, plus new PoC-based regression checks for both the traversal and legitimate same-directory cases), and can share this fix on request or via a private fork if invited.
Verification
Dynamically confirmed on v8.5.16 (current npm release / repo HEAD) via a standalone Node.js harness against
lib/postcss.js: a "secret".mapfile placed two directories outside a simulated project directory was read via a craftedsourceMappingURLcomment in otherwise-innocuous CSS, with itssourcesContentappearing verbatim inresult.map.toString()— with nomapoption set by the caller. A second harness confirmed the simpler no-fromcase reads an absolute path directly. A third harness confirmedmap: falseis the only current workaround. The attached fix branch closes both vectors while keeping all 660 existing unit tests green.Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Release Notes
postcss/postcss (postcss)
v8.5.18Compare Source
opts.fromfolder for security reasons (useunsafeMap: trueto disable the check).v8.5.17Compare Source
Maximum call stack size exceedederror.postcss.fromJSON().Input#origin()for unmapped end position (by @chatman-media).Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Never, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.