Safeguard
Developer Tools•

Can you ban an unsafe function in ESLint without writing a custom rule?

Yes. ESLint's no-restricted-syntax takes AST selectors and custom messages, so you can ban a call or pattern with a few lines of config and no plugin.

Safeguard Security Team
4 min read

Yes. ESLint's no-restricted-syntax rule accepts AST selectors and an optional custom message, so you can ban a function call or code pattern with a few lines of configuration and no plugin. Use it first, and write a custom rule only when selectors cannot express what you need.

What the rule does

ESLint's documentation describes no-restricted-syntax as a way to disallow user-defined syntax without creating a separate rule for every feature. For JavaScript, elements are identified by ESTree node types, and the rule also accepts AST selectors for more precise control. It can be used with any language you lint using ESLint, and the docs point to Code Explorer and the typescript-eslint Playground for viewing node types.

Options are a list. Each item is either a selector string, or an object with a selector and a message. When a message is given, ESLint uses it when reporting.

Example

// eslint.config.js
export default [
  {
    rules: {
      "no-restricted-syntax": [
        "error",
        {
          selector: "CallExpression[callee.name='runShell']",
          message: "Do not call runShell directly. Use safeExec from the process helpers."
        }
      ]
    }
  }
];

The selector reads as: a call expression whose callee name is runShell. The attribute syntax is the same family used in the documentation's own examples, such as selecting a call where the callee name is setTimeout and the argument count is not two.

Related built in option for imports

For modules, the no-restricted-imports rule lets you disallow named modules, with a custom message per module that is appended to the default error message. The docs note it applies to static imports only, not dynamic ones, which is a gap you should be aware of.

Config or custom rule

NeedUse
Ban a function or syntax formno-restricted-syntax
Ban an importno-restricted-imports
Ban a call only when an argument is not a literalA selector may do it, check, or a custom rule
Logic across several nodes, or checking scopeCustom rule
An autofixCustom rule
Several options and per option documentationCustom rule

Steps

  1. Write the pattern in one sentence.
  2. Open Code Explorer and find the node type and fields.
  3. Write a selector for it.
  4. Add a message with the replacement.
  5. Test on a file that should fail and one that should not. You can still do this with ESLint's own test tooling, or with a small fixture directory and a CI check.
  6. Roll out as warn, then error.

Limits to remember

  • A selector on a name does not follow aliases. Importing the function under another name evades it.
  • Dynamic imports are not covered by the import rule.
  • A long list of selectors in one config is hard to document and own. If you pass a handful, move them into a dedicated custom rule with its own README.
  • Messages are only as useful as you make them, so name the replacement.

Quick check

Do I need to publish a plugin to use selectors?

No. The rule is part of ESLint and is configured in your config file.

How do I find the right selector?

Paste a sample of the code into Code Explorer, read the node types and field values, and build a selector from them.

Safeguard's scanning covers dependencies and SBOMs, and its reachability analysis helps show which findings your code can actually call. You can run a free scan on a repository.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.