Skip to content

Crash: stack overflow / integer overflow on deeply nested CSS (found via fuzzing) #1155

@jasikpark

Description

@jasikpark

Summary

Deeply nested { in CSS input causes a crash. On Linux/CI the panic message is attempt to add with overflow in lightningcss/src/printer.rs. On macOS the same input causes a stack overflow via mutual recursion between StyleRule::to_css_base and CssRuleList::to_css.

Affected versions

  • lightningcss 1.0.0-alpha.70 (confirmed)
  • Likely all versions with the same recursive printer structure

Reproducer

Minimized input (525 bytes) found via cargo-fuzz. Decode this base64 to a file and pass it to the Printer:

ACwACQkAVgAJVkEAAAlWewB7TgB7AHtOU04AeyYscywmLAB7AHsmLHMsJiwAe3VzZXItaW52YWxpZAB7TiYsAHsALAB7Tk5TAHsAewAsAAkJAFYACVZBAAAJVnsAe04AewB7TlNOAHsmLHMsJiwAewB7JixzLCYsAHt1c2UAe04mLAB7ACwAe05OUwB7AHtOAHsmLHMsJiwAewB7JixzLCYsAHsAe04mLAB7ACwAewB7TgB7AHtOU04AewB+entze04AewB7TgB7AHtOU04AeyYsc3sAe05TAHtOAHsAe05TTgB7AH56e3N7TgB7AHtOTgB7JixzLCYsAHsAeyYscywmLAB7AHtOJiwAewAsTiYsAHsALAB7Tk5TAHsAe04AeyYscywmLAB7AHsmLHMsJiwAewB7TiYsAHsALAB7AHtOAHsAe05TTgB7AH56e3N7TgB7AHtOAHsAe05TTgB7JixzewB7TlMAe04AewB7TlNOAHsAfnp7c3tOAHsAe05OAHsmLHMsJiwAewB7JixzLCYsAHsAe04mLAB7ACwAewB7TgB7AHtOU04AewB+entze04AAHsAe04AewB7TlNOAHsAfnp7c3tOAHsAe04AewB7TlNOAHsmLHN7AHtOUwB7TgB7AHtOU04AewB+entze04AewB7TlNOAHsAfnoNEQAAAAB+AHt+e3MAe05T

The fuzz target and artifact are available in this PR for compiler-rs (an Astro component compiler that uses lightningcss for CSS scoping): withastro/compiler-rs#5

The input can also be exercised directly:

use lightningcss::stylesheet::{StyleSheet, ParserOptions, PrinterOptions};

let css = /* base64-decoded bytes above, interpreted as lossy UTF-8 */;
let sheet = StyleSheet::parse(css, ParserOptions::default()).unwrap();
sheet.to_css(PrinterOptions::default()); // panics

Observed behaviour

Linux x86-64 (CI):

thread '<unnamed>' panicked at lightningcss-1.0.0-alpha.70/src/printer.rs:219:5:
attempt to add with overflow

macOS arm64 (local):

thread '<unnamed>' panicked at lightningcss-1.0.0-alpha.70/src/printer.rs:219:5:
attempt to add with overflow

Stack trace (macOS) shows 200+ alternating frames:

StyleRule::to_css_base  (lightningcss/src/rules/style.rs)
CssRuleList::to_css     (lightningcss/src/rules/mod.rs)
StyleRule::to_css_base  (lightningcss/src/rules/style.rs)
...

The integer overflow occurs in the indentation arithmetic inside the printer once the recursion depth is large enough that the indent counter wraps.

Root cause

StyleRule::to_css_base calls CssRuleList::to_css for nested rules, which calls back into StyleRule::to_css_base — mutual recursion with no depth limit. lightningcss's parser accepts deeply nested CSS, so the printer receives input that overflows both the stack and the indent counter.

Expected behaviour

to_css should return an error for pathologically nested CSS rather than panicking. Any real-world CSS nesting limit (a few hundred levels) would be safe.

Fix suggestion

Add a depth counter to the printer (or parser) and return Err when the limit is exceeded. A limit of a few hundred levels is more than sufficient for real-world CSS.

Environment

  • lightningcss 1.0.0-alpha.70
  • Rust stable / nightly
  • Reproduced on Linux x86-64 (CI) and macOS arm64 (local)
  • Found via cargo-fuzz (css_scope_no_panic target)

Note: this issue was drafted with AI assistance (Claude), which also helped build the fuzzing setup, artifact minimization, and root cause analysis.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions