CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

testland/language-native-sast

Use when a repo needs security linting inside its own toolchain: Bandit for Python, gosec for Go, eslint-plugin-security and no-unsanitized for JavaScript/TypeScript, or PMD's Apex rules for Salesforce, with justified suppressions, baselines for legacy code, SARIF and CI gates.

Quality

87%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

eslint-security.mdreferences/

ESLint security plugins - JS/TS language-native SAST

Per-tool reference for language-native-sast. Two npm plugins add a security lint layer inside the standard ESLint pipeline, no external server required. They emit JSON or SARIF for a multi-scanner triage step.

Per github.com/eslint-community/eslint-plugin-security:

"This project will help identify potential security hotspots, but finds a lot of false positives which need triage by a human."

Per github.com/mozilla/eslint-plugin-no-unsanitized, the no-unsanitized plugin adds "basic security checks" for DOM sink operations (innerHTML, insertAdjacentHTML, document.write).

Install

npm install --save-dev eslint-plugin-security
npm install --save-dev eslint-plugin-no-unsanitized

For SARIF output, per github.com/microsoft/sarif-js-sdk:

npm install --save-dev @microsoft/eslint-formatter-sarif

Flat config setup (ESLint 8.23+ and ESLint 9+)

Per esp-sec and esp-xss:

// eslint.config.js
import pluginSecurity from "eslint-plugin-security";
import nounsanitized from "eslint-plugin-no-unsanitized";

export default [
  pluginSecurity.configs.recommended,
  nounsanitized.configs.recommended,
];

For legacy .eslintrc configs, per esp-sec:

module.exports = {
  extends: ["plugin:security/recommended-legacy"],
};

Rule catalog

Per esp-sec, configs.recommended enables all 14 detect-* rules:

Rule IDDetects
security/detect-bidi-charactersUnicode bidi override characters (trojan-source attacks)
security/detect-buffer-noassertBuffer calls with the noAssert flag set
security/detect-child-processchild_process use and non-literal exec() calls
security/detect-disable-mustache-escapeTemplate engines with escaping disabled
security/detect-eval-with-expressioneval(variable) - arbitrary code execution
security/detect-new-buffernew Buffer(non-literal) - deprecated unsafe API
security/detect-no-csrf-before-method-overrideExpress middleware ordering that bypasses CSRF
security/detect-non-literal-fs-filenamefs calls with variable filenames - path traversal
security/detect-non-literal-regexpRegExp(variable) - potential ReDoS
security/detect-non-literal-requirerequire(variable) - dynamic require
security/detect-object-injectionobj[variable] property access - prototype injection
security/detect-possible-timing-attacksInsecure string comparisons (==, ===) for secrets
security/detect-pseudoRandomBytescrypto.pseudoRandomBytes and Math.random for security
security/detect-unsafe-regexReDoS-vulnerable regular expressions

Per esp-xss, configs.recommended enables:

Rule IDDetects
nounsanitized/methodUnsafe calls: insertAdjacentHTML, document.write, document.writeln with variable arguments
nounsanitized/propertyUnsafe assignments: element.innerHTML = variable, element.outerHTML = variable

Safe alternatives per esp-xss: construct DOM nodes with createElement and set textContent or classList rather than assigning raw HTML strings.

False-positive triage

security/detect-object-injection is the highest-volume false positive: any obj[key] access triggers it, including safe patterns like array indexing. Standard triage approaches:

Per-line suppression with mandatory justification:

// eslint-disable-next-line security/detect-object-injection
// Reason: key is validated against allowedKeys before this point
// Reviewer: eng@example.com (2026-06-04)
// Expires: 2026-12-04
const value = config[key];

Block-level suppression for generated or vendored code:

/* eslint-disable security/detect-object-injection */
// Reason: auto-generated lookup table; keys are compile-time constants
/* eslint-enable security/detect-object-injection */

Rule-level severity downgrade when a rule produces only noise on a specific codebase:

// eslint.config.js
export default [
  pluginSecurity.configs.recommended,
  {
    rules: {
      "security/detect-object-injection": "warn", // downgrade from error
    },
  },
];

Suppression cadence: audit all eslint-disable comments quarterly. Suppressions without Reason: + Reviewer: + Expires: are treated as unreviewed debt.

SARIF output for GitHub Code Scanning

Per sarif-sdk, the @microsoft/eslint-formatter-sarif package cannot be invoked with the abbreviated -f sarif form because its name is scoped. Use the full package name:

npx eslint \
  --format @microsoft/eslint-formatter-sarif \
  --output-file eslint-security.sarif \
  "src/**/*.{js,ts}"

To embed analyzed source content in the SARIF output:

SARIF_ESLINT_EMBED=true npx eslint \
  --format @microsoft/eslint-formatter-sarif \
  --output-file eslint-security.sarif \
  "src/**/*.{js,ts}"

JSON output for multi-scanner triage

Per eslint.org/docs/latest/use/command-line-interface, --format json produces an array of file result objects, each with a messages array containing ruleId, severity, line, column, and message. Feed eslint-security.json into a multi-scanner triage step alongside semgrep.json and other scanner outputs; normalize ruleId to CWE for deduplication across scanners.

CI integration with gating

Per eslint-cli, ESLint exit codes: 0 = no errors; 1 = errors found; 2 = config error. Gate CI on exit code 1:

# .github/workflows/security-lint.yml
name: Security Lint
on: [push, pull_request]

jobs:
  eslint-security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: "22" }
      - run: npm ci
      - name: Run security lint (JSON for triager)
        run: |
          npx eslint \
            --format json \
            --output-file eslint-security.json \
            "src/**/*.{js,ts}" || true
      - name: Run security lint (SARIF for Code Scanning)
        run: |
          npx eslint \
            --format @microsoft/eslint-formatter-sarif \
            --output-file eslint-security.sarif \
            "src/**/*.{js,ts}"; exit $?
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: eslint-security.sarif

The JSON pass uses || true so SARIF upload still runs on failure; the SARIF pass propagates the real exit code so the job fails on errors.

Example

Triggering finding:

const userData = req.body;
element.innerHTML = userData.bio; // nounsanitized/property
const file = fs.readFileSync(req.query.path); // security/detect-non-literal-fs-filename

ESLint output (stylish):

src/profile.js
  12:3  error  Unsafe assignment to innerHTML  nounsanitized/property
  18:3  error  Found non-literal argument to readFileSync  security/detect-non-literal-fs-filename

Safe rewrites:

// XSS: use textContent for plain text; DOMPurify for rich HTML
element.textContent = userData.bio;
// or: element.setHTML(sanitize(userData.bio));

// Path traversal: validate against an allowlist
const allowed = ["/var/data/a.txt", "/var/data/b.txt"];
if (!allowed.includes(req.query.path)) throw new Error("invalid path");
const file = fs.readFileSync(req.query.path);

Limitations

  • detect-object-injection fires on all variable-keyed property accesses; expect high false-positive volume on data-heavy code. Pair with a code review step rather than blocking CI on it alone.
  • Neither plugin performs cross-file taint tracking; for taint flow across module boundaries, pair with semgrep-rules or codeql-queries.
  • eslint-plugin-security does not cover server-side template injection or SQL injection natively; use Semgrep p/owasp-top-ten for those patterns.
  • Rules run at parse time, not at runtime; dynamic injection via eval called through a proxy chain will not be caught.

Sources

  • esp-sec - full rule list, installation, flat config + legacy config
  • esp-xss - method and property rules, safe DOM alternatives
  • sarif-sdk - @microsoft/eslint-formatter-sarif, scoped -f usage, SARIF_ESLINT_EMBED
  • eslint-cli - --format, --output-file, exit codes

SKILL.md

tile.json