Skip to content

Commit

Permalink
feat(lint/noGlobalEval): add rule (#1133)
Browse files Browse the repository at this point in the history
Co-authored-by: Victorien Elvinger <victorien@elvinger.fr>
  • Loading branch information
yo-iwamoto and Conaclos authored Jan 4, 2024
1 parent c98a030 commit b88f8b7
Show file tree
Hide file tree
Showing 19 changed files with 1,023 additions and 70 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ Biome now scores 97% compatibility with Prettier and features more than 180 lint
}
```
- Add [noGlobalEval](https://biomejs.dev/linter/rules/no-global-eval) that reports any use of the global `eval`.
Contributed by @you-5805
#### Enhancements
- Address [#959](https://github.com/biomejs/biome/issues/959) and [#1157](https://github.com/biomejs/biome/issues/1157). [noEmptyInterface](https://biomejs.dev/linter/rules/no-empty-interface) no longer reports empty interfaces that extend a type. Contributed by @Conaclos
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ expression: content
# Emitted Messages

```block
The logs directory is available at:
The daemon logs are available in the directory:
```

Expand Down

This file was deleted.

1 change: 1 addition & 0 deletions crates/biome_diagnostics_categories/src/categories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ define_categories! {
"lint/nursery/noDefaultExport": "https://biomejs.dev/linter/rules/no-default-export",
"lint/nursery/noDuplicateJsonKeys": "https://biomejs.dev/linter/rules/no-duplicate-json-keys",
"lint/nursery/noEmptyBlockStatements": "https://biomejs.dev/linter/rules/no-empty-block-statements",
"lint/nursery/noGlobalEval": "https://biomejs.dev/linter/rules/no-global-eval",
"lint/nursery/noImplicitAnyLet": "https://biomejs.dev/linter/rules/no-implicit-any-let",
"lint/nursery/noInvalidUseBeforeDeclaration": "https://biomejs.dev/linter/rules/no-invalid-use-before-declaration",
"lint/nursery/noMisleadingCharacterClass": "https://biomejs.dev/linter/rules/no-misleading-character-class",
Expand Down
2 changes: 2 additions & 0 deletions crates/biome_js_analyze/src/semantic_analyzers/nursery.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use crate::semantic_services::Semantic;
use biome_analyze::{context::RuleContext, declare_rule, Rule, RuleDiagnostic};
use biome_console::markup;
use biome_js_syntax::{global_identifier, AnyJsExpression};
use biome_rowan::AstNode;

declare_rule! {
/// Disallow the use of global `eval()`.
///
/// The `eval()` function evaluates the passed string as a _JavaScript_ code.
/// The executed code can access and mutate variables in the scope where the function is called.
///
/// The use of `eval()` exposes to [security risks and performance issues](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_eval!).
/// If the executed code is somehow affected by a malicious party,
/// then you may end up executing malicious code with the privileges of the caller.
/// Moreover, changing variables in the caller's scope is expensive in modern _JavaScript_ interpreters.
///
/// Source: https://eslint.org/docs/latest/rules/no-eval
///
/// ## Examples
///
/// ### Invalid
///
/// ```js,expect_diagnostic
/// eval("var a = 0");
/// ```
///
/// ```js,expect_diagnostic
/// (0, globalThis.eval)("var a = 0")
/// ```
///
/// ```js,expect_diagnostic
/// f(eval);
/// ```
///
/// ```js,expect_diagnostic
/// const aliasedEval = eval;
/// ```
///
/// ### Valid
///
/// ```cjs
/// function f(eval) {
/// eval("let a = 0;");
/// }
/// ```
///
/// The rule is not able to detect cases where the global object is aliased:
///
/// ```js
/// let foo = globalThis;
/// foo.eval("let a = 0;");
/// ```
pub(crate) NoGlobalEval {
version: "next",
name: "noGlobalEval",
recommended: true,
}
}

impl Rule for NoGlobalEval {
type Query = Semantic<AnyJsExpression>;
type State = ();
type Signals = Option<Self::State>;
type Options = ();

fn run(ctx: &RuleContext<Self>) -> Self::Signals {
let node = ctx.query();
let model = ctx.model();
let (reference, name) = global_identifier(node)?;
if name.text() != "eval" {
return None;
}
model.binding(&reference).is_none().then_some(())
}

fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> {
let node = ctx.query();
Some(RuleDiagnostic::new(
rule_category!(),
node.range(),
markup! {
<Emphasis>"eval()"</Emphasis>" exposes to security risks and performance issues."
},
).note(markup! {
"See the "<Hyperlink href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_eval!">"MDN web docs"</Hyperlink>" for more details."
})
.note(
markup! {
"Refactor the code so that it doesn't need to call "<Emphasis>"eval()"</Emphasis>"."
}))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
var foo = "foo";
eval(foo);

eval("foo");

(0, eval)("foo");

(0, window.eval)("foo");

(0, window["eval"])("foo");

var EVAL = eval;
EVAL("foo");

var EVAL = this.eval;
EVAL("foo");

("use strict");
var EVAL = this.eval;
EVAL("foo");

() => {
this.eval("foo");
};

() => {
"use strict";
this.eval("foo");
};

("use strict");
() => {
this.eval("foo");
};

() => {
"use strict";
() => {
this.eval("foo");
};
};

(function (exe) {
exe("foo");
})(eval);

window.eval("foo");

window.window.eval("foo");

window.window["eval"]("foo");

this.eval("foo");

("use strict");
this.eval("foo");

function foo() {
this.eval("foo");
}

var EVAL = globalThis.eval;
EVAL("foo");

globalThis.eval("foo");

globalThis.globalThis.eval("foo");

globalThis.globalThis["eval"]("foo");

(0, globalThis.eval)("foo");

(0, globalThis["eval"])("foo");
Loading

0 comments on commit b88f8b7

Please sign in to comment.