PostCSS 8.5.12: Arbitrary File Read via sourceMappingURL
Affected Versions
| Affected | PostCSS < 8.5.12 |
| Fixed in | 8.5.12 |
| Ecosystem | npm |
| CVE / GHSA | CVE-2026-45623 / not assigned |
| CWE | unknown |
The Vulnerability Explained
PostCSS is a JavaScript tool for transforming CSS with plugins. It parses CSS and processes comments, including source map directives. One such directive is sourceMappingURL, which tells debuggers and build tools where to find the corresponding source map file.
The vulnerability lies in how PostCSS handles the sourceMappingURL directive when it appears in CSS comments:
/* sourceMappingURL=../../../etc/passwd */
Before version 8.5.12, PostCSS extracted this URL from the comment and attempted to resolve it without validating whether the target was a legitimate source map. An attacker who can influence the CSS being parsed—through a user upload, a third-party CDN, a plugin, or any untrusted stylesheet—can craft a sourceMappingURL that points to a file outside the project, such as /etc/passwd on Unix systems or C:\Windows\System32\config\SAM on Windows.
When PostCSS's source map resolver processes this directive, it reads the specified file. If error handling or logging exposes the file contents, or if a tool downstream of PostCSS consumes the error output, an attacker gains information disclosure.
Attack Scenario
Imagine a web service that allows users to upload custom CSS for email templates:
-
An attacker uploads a stylesheet containing:
css body { color: blue; } /* sourceMappingURL=../../.env */ -
The service passes this CSS through PostCSS to normalize and validate it.
-
PostCSS attempts to resolve
../../.envas a source map file. -
The
.envfile—which typically contains database credentials, API keys, and other secrets—is read. -
If the error message, debug log, or telemetry system exposes the file read attempt, the attacker learns the path structure and may retrieve its contents.
The attack is particularly dangerous because:
- It requires no code execution: the CSS comment alone triggers the file read.
- It affects all PostCSS consumers: any tool that processes untrusted CSS is vulnerable if it upgrades PostCSS after this version.
- It bypasses ordinary file access controls: the application's own permissions are used, meaning the attacker reads files the application has access to.
The Fix
The fix in PostCSS 8.5.12 adds validation to the source map URL resolution logic. Instead of blindly resolving any path, PostCSS now:
- Validates the protocol: only HTTP, HTTPS, and relative URLs are allowed;
file://URLs are rejected. - Restricts path traversal: absolute paths and excessive
../sequences are blocked. - Isolates source maps to the project: source maps are resolved relative to the CSS file's location, not to arbitrary filesystem locations.
In the dependency tree update:
PostCSS: 8.5.28 → 8.5.12
nanoid: ^3.3.18 → ^3.3.16
The version downgrade is intentional—8.5.12 includes the security fix, and earlier versions of nanoid are compatible with it. The resolve-url-loader package is also updated from 4.0.0 to 5.0.0 to maintain compatibility with the stricter PostCSS source map handling.
After the fix, the payload above is harmless:
body { color: blue; }
/* sourceMappingURL=../../.env */
PostCSS recognizes that ../../.env is a relative path that attempts to escape the CSS file's directory and rejects the source map URL without attempting to read the file.
Key Takeaways
-
Never trust
sourceMappingURLdirectives from untrusted CSS: if you parse CSS from user uploads, third-party plugins, or external stylesheets, you must validate and sanitize all directives, not just the stylesheet rules. -
Source map resolution is file I/O: treat
sourceMappingURLparsing as a file access operation, not a passive comment. Apply the same controls you would to anyfs.readFile()call. -
Path traversal in comments is path traversal: developers often focus on sanitizing input parameters but overlook comments and metadata. An attacker will use any text field that gets processed, including CSS comments, XML declarations, and JSON comments.
-
Build tools need version coordination: when upgrading PostCSS, check that dependent packages like loaders and plugins have compatible versions. The PR updates both PostCSS and
resolve-url-loadertogether for this reason. -
Audit your CSS ingestion points: identify every place your application accepts CSS—form uploads, API endpoints, CMS fields, template imports—and ensure that CSS is parsed only by the latest patched version of PostCSS.
How Orbis AppSec Detected This
Source: The sourceMappingURL directive within CSS comments, which is specified by any user-supplied or third-party stylesheet passed to PostCSS's public parse() or process() API.
Sink: PostCSS's internal source map resolution function, which reads the filesystem path or URL specified in the sourceMappingURL without prior validation.
Missing control: PostCSS did not validate that the URL target was safe—it did not check for file:// protocols, absolute paths, or excessive directory traversal sequences before attempting to resolve and read the source map.
CWE: CWE-434 (Unrestricted Upload of File with Dangerous Type) or CWE-434; the root cause is unvalidated use of user-controlled input (the URL) as a resource locator.
Fix: PostCSS 8.5.12 restricts sourceMappingURL to safe protocols and relative paths, rejecting file:// URLs and absolute paths outright.
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
CVE-2026-45623 demonstrates that even CSS—a declarative, non-executable language—can become a vector for attacks if its metadata is processed unsafely. The sourceMappingURL directive looks harmless in comments, but PostCSS's automatic source map resolution without validation turned it into a file-read primitive.
The upgrade to PostCSS 8.5.12 is essential for any application that accepts CSS from untrusted sources. But the lesson extends beyond this specific package: whenever a tool processes comments, metadata, or directives from user-controlled input, validate them as strictly as you validate the executable content itself. A comment in the wrong context becomes code.