🛡️ CVE-2026-45623 — postcss
Description
PostCSS: Arbitrary file read and information disclosure via attacker-controlled sourceMappingURL in CSS comments
Summary
PostCSS's PreviousMap parses the /*# sourceMappingURL=PATH */ comment from any CSS string passed to process() and dereferences PATH against the local filesystem with no scheme, allowlist, or traversal check. An attacker who controls the CSS input can cause the host process to read any file readable by Node and leak the first ~10 bytes of its content through the resulting JSON.parse SyntaxError message. The bug also yields a precise file-existence oracle and a controllable-read primitive that may be combined with large-file targets for DoS. The behaviour is triggered with PostCSS's default options — no from, no map, no plugins required — and is therefore reachable from any pipeline that runs untrusted CSS through PostCSS (CMS themes, user-uploaded styles, browser-extension/userstyle processors, build pipelines for third-party packages, blog comment renderers, etc.).
Details
The dangerous chain lives in lib/previous-map.js and is wired into every Input construction at lib/input.js:70-77.
Input constructor (lib/input.js:70-77):
```js
if (pathAvailable && sourceMapAvailable) {
let map = new PreviousMap(this.css, opts)
if (map.text) {
this.map = map
let file = map.consumer().file
if (!this.file && file) this.file = this.mapResolve(file)
}
}
```
PreviousMap constructor (lib/previous-map.js:17-29):
```js
constructor(css, opts) {
if (opts.map === false) return
this.loadAnnotation(css)
this.inline = this.startWith(this.annotation, 'data:')
let prev = opts.map ? opts.map.prev : undefined
let text = this.loadMap(opts.from, prev)
...
}
```
Note opts.map === false is the only short-circuit. With default options (opts.map === undefined), the rest of the constructor — including the filesystem read — executes.
loadAnnotation (lib/previous-map.js:72-84) extracts the URL without sanitisation:
```js
loadAnnotation(css) {
let comments = css.match(/\/\*\s*# sourceMappingURL=/g)
if (!comments) return
let start = css.lastIndexOf(comments.pop())
let end = css.indexOf('*/', start)
if (start > -1 && end > -1) {
this.annotation = this.getAnnotationURL(css.substring(start, end))
}
}
```
getAnnotationURL (lib/previous-map.js:59-61) only strips the /*# sourceMappingURL= prefix and trims whitespace — no scheme check, no path normalisation, no allowlist.
loadMap (lib/previous-map.js:124-128) — when prev is absent and the annotation is not an inline data: URI:
```js
} else if (this.annotation) {
let map = this.annotation
if (file) map = join(dirname(file), map)
return this.loadFile(map)
}
```
- If
opts.fromis unset,fileis undefined and the raw attacker-supplied path (e.g./etc/passwd) is used directly. - If
opts.fromis set,path.join(dirname(file), attackerPath)is used.path.joindoes not block..segments, so../../../../../etc/passwdresolves outside the intended directory.
loadFile (lib/previous-map.js:86-92) is the sink:
```js
loadFile(path) {
this.root = dirname(path)
if (existsSync(path)) {
this.mapFile = path
return readFileSync(path, 'utf-8').toString().trim()
}
}
```
The bytes are stored in this.text. Input immediately invokes map.consumer() (lib/input.js:74), which constructs a SourceMapConsumer (lib/previous-map.js:33). When the file is not valid source-map JSON (the common case), source-map-js calls JSON.parse, and V8's SyntaxError message embeds the first ~10 bytes of the file content:
```
Unexpected token 'r', "root:x:0:0"... is not valid JSON
```
This error is propagated back to the caller. Any application that surfaces PostCSS errors (logs, HTTP 500 responses, build-tool output, debug pages) discloses those bytes to the attacker.
Trust-boundary analysis:
- Attacker controls: CSS input passed to
postcss().process(css, opts?). - Server resources: any file readable by the Node process — typically including app config, environment files, SSH keys,
/etc/passwd,/proc/self/environ, etc. - No mitigations: there is no path validation, scheme allowlist, traversal check, or symlink check. The only relevant check (
startWith(annotation, 'data:')) routes inline URIs todecodeInline; everything else hitsloadFile.
Primitives obtained:
- (a) Arbitrary file read — bytes loaded into Node memory.
- (b) Information disclosure — first ~10 bytes leaked via
JSON.parseSyntaxErrormessage. - (c) File-existence oracle — non-existent paths return silently from
loadFile(existsSyncis false → returns undefined → no map text → no consumer call → no error). Existent non-JSON paths throw. Existent JSON paths succeed silently. Three distinguishable states. - (d) DoS primitive — directing the read at
/dev/zero, very large files, or device files can stall or crash the process.
PoC
All commands execut
How this vulnerability can be exploited
This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality high, integrity none, availability none.
Weakness class
CVE-2026-45623 is classified as CWE-200: Exposure of Sensitive Information. Information that should stay internal is disclosed to someone who is not authorised to see it.
Affected software
CVE-2026-45623 is recorded against 1 package.
- postcss
Timeline and source
Published on 23 July 2026 and last revised on 7 August 2026. A public exploit is known to exist, which raises the urgency of patching considerably. Record sourced from OSV.
References
github.com (Web)
github.com (Web)
github.com (Web)
github.com (Package)
github.com (Web)
Details
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| postcss | — | — |
References
Similar Threats
- Unknown CLSA-2026-1774830263
- Unknown CLSA-2026-1776299672
- Unknown CLSA-2026-1777509599
- Unknown CLSA-2026-1779065184
- Unknown CLSA-2026-1779065188
More CVE 2026 advisories
Browse all of CVE 2026 in the advisory index.
Exploit Protection
Are you running postcss?
CVE-2026-45623 carries CVSS 8.0 High rating and a public exploit already exists. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.
Check My Site For CVE-2026-45623 →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.