Skip to main content

@codelaw/rules-security-js · codelaw-rules-security-js

codelaw's JavaScript (Node, the browser, Express) security rules: 66 of them, each mapped to a CWE and an OWASP Top 10:2025 category, each with a fix class and examples in all four languages. One of codelaw's first-party rule packs (SR-RULE-PACKS). The same files ship on npm as @codelaw/rules-security-js and on PyPI as codelaw-rules-security-js: a Python repository with JavaScript in it gets them too.

# codelaw.toml
extends = ["codelaw:js/recommended", "codelaw:sec-js/recommended"]
preview = true   # every rule is `preview` until a corpus run promotes it

codelaw init does not add it: a security pack is chosen, not detected. The rules run on JS, JSX, TS and TSX files; the TypeScript-only rules (Angular, NestJS, Prisma, typed casts) are in security-ts, which extends this pack.

Presets

preset rules ported from
sec-js/recommended 55 high-confidence rules, at error
sec-js/strict 66 sec-js/recommended and the heuristic rules, at warn

recommended holds the 55 high-confidence rules, at error; strict adds the 11 heuristic ones, at warn, so a team can start without noise. 17 rules offer a mechanical fix (auto 0, suggest 17); the other 49 are manual, and each names the safe API in its How to fix steps, which the codelaw-fix skill walks through.

Rules

Every rule carries security: { cwe, owasp, severity } (SR-RULE-FORMAT decision 2a), so

  • its finding names the CWE (sec-js/<rule> (CWE-79) …);
  • codelaw rules --tag cwe:79 and --tag owasp:A05 find it, and codelaw rules --security-coverage puts it in the OWASP Top 10:2025 matrix;
  • SARIF carries its security and external/cwe/cwe-<n> tags and a security-severity that GitHub code scanning ranks by (SR-CLI-MCP decision 4).

Injection and code execution

rule rule says CWE OWASP 2025 fix preset
sec-js/no-eval No eval, new Function or string timers 94 A05 manual recommended
sec-js/no-child-process-shell No shell command built from a value 78 A05 manual recommended
sec-js/no-sql-template No SQL built from a template or concatenation 89 A05 manual recommended
sec-js/no-nosql-injection No request object passed straight to a query, no $where 943 A05 manual recommended
sec-js/no-xpath-injection No XPath built from a template or concatenation 643 A05 manual recommended
sec-js/no-ldap-injection No LDAP filter built from a template or concatenation 90 A05 manual recommended
sec-js/no-ssti No template compiled from a request, no template data taken whole from a request 1336, 73 A05 manual recommended
sec-js/no-header-injection No response header value taken from a request 113 A05 manual recommended
sec-js/no-log-injection No request data written to a log unchanged 117 A09 manual strict
sec-js/no-format-string No request data as a format string 134 A05 suggest strict
sec-js/no-non-literal-require No require or import of a computed module name 829, 95 A08 manual recommended
sec-js/no-unvalidated-dynamic-method No method chosen by a request value 470 A05 manual recommended
sec-js/no-xxe No XML entity expansion 611, 776 A05 suggest recommended
sec-js/no-unsafe-deserialize No deserializer that builds objects or runs code 502 A08 suggest recommended
sec-js/no-new-buffer No new Buffer, no noAssert 119 A06 suggest recommended
sec-js/no-unsafe-regex No regular expression that can run for ever, no regular expression built from a request 1333 A06 manual strict
sec-js/no-prototype-pollution No request value used as a key to write or merge 1321 A08 manual recommended

Cross-site scripting and the browser

rule rule says CWE OWASP 2025 fix preset
sec-js/no-unsanitized-html No HTML written from a value that is not a literal 79 A05 suggest recommended
sec-js/no-dangerously-set-inner-html No dangerouslySetInnerHTML from a value that is not sanitized 79 A05 manual recommended
sec-js/no-javascript-url No javascript: URL, no navigation to a URL taken from the address 79 A05 manual recommended
sec-js/postmessage-origin postMessage names its target, a message handler checks the sender 346 A01 manual recommended
sec-js/no-jquery-html-sink No jQuery call that parses a built string as HTML 79 A05 manual recommended
sec-js/no-window-open-opener No window.open without noopener 1022 A05 suggest recommended
sec-js/no-dynamic-script-src No script or frame source taken from a value that is not a literal 829 A08 manual recommended
sec-js/no-incomplete-url-check No URL checked with a substring test 20 A01 manual recommended
sec-js/no-incomplete-sanitization No escaping that stops at the first match, no one-pass stripping 116 A05 suggest recommended
sec-js/no-bad-tag-filter No regular expression that filters HTML tags 116, 185 A05 manual recommended
sec-js/angularjs-sce-disabled No AngularJS strict contextual escaping switched off 79 A05 manual strict
sec-js/no-bidi-characters No hidden bidirectional control characters in code — A08 suggest recommended
sec-js/no-document-cookie-token No token or session written to document.cookie 1004 A07 manual recommended
sec-js/no-token-in-web-storage No token kept in localStorage or sessionStorage 922 A07 manual recommended
sec-js/no-server-env-in-client No server environment variable in a client component, no secret in a public one 200 A02 manual recommended
sec-js/no-electron-insecure No insecure Electron window setting 79, 829 A02 suggest recommended

Access, requests and the server

rule rule says CWE OWASP 2025 fix preset
sec-js/no-path-traversal No file path taken from a request 22 A01 manual recommended
sec-js/no-archive-slip No archive entry name written to disk unchecked 22 A01 manual recommended
sec-js/no-open-redirect No redirect to an address taken from a request 601 A01 manual recommended
sec-js/no-ssrf No request made to an address taken from a request 918 A01 manual recommended
sec-js/no-tls-bypass No switching off of certificate checks 295 A04 suggest recommended
sec-js/no-cleartext-http No request made over http:// 319 A04 manual recommended
sec-js/no-cors-wildcard-credentials No CORS that allows every origin together with credentials 942 A02 manual recommended
sec-js/express-hardening An Express app turns off x-powered-by or uses helmet 200 A02 suggest strict
sec-js/helmet-config helmet is not given false for a header it sets 693 A02 manual recommended
sec-js/cookie-flags A cookie sets httpOnly, secure and sameSite 614, 1004 A02 suggest recommended
sec-js/express-session-secret express-session has a secret from the environment and a secure cookie 798, 614 A07 manual recommended
sec-js/no-csrf-before-method-override No method-override before the CSRF check 352 A01 suggest recommended
sec-js/missing-rate-limit A login or reset route has a rate limit 770, 307 A07 manual strict
sec-js/no-sensitive-get-query No password, token or secret read from the query string 598 A04 manual recommended
sec-js/no-mass-assignment No request body written straight into a model 915 A01 manual recommended
sec-js/no-user-controlled-auth-bypass No privileged branch decided by a request value 807 A01 manual strict
sec-js/upload-limits multer has size limits and a file filter 434, 770 A06 manual recommended
sec-js/graphql-hardening A GraphQL server limits query depth and cost, and hides introspection 200, 770 A02 manual strict
sec-js/no-non-literal-fs-filename No file path that is not a literal 22 A01 manual strict
sec-js/no-stack-trace-response No error object or stack trace in a response 209 A10 manual recommended

Cryptography, secrets and models

rule rule says CWE OWASP 2025 fix preset
sec-js/no-weak-hash No MD5 or SHA-1 327 A04 manual recommended
sec-js/no-weak-cipher No createCipher, no DES, RC4, Blowfish or ECB 327 A04 manual recommended
sec-js/no-weak-key-size No short RSA key, no weak elliptic curve 326 A04 suggest recommended
sec-js/no-hardcoded-crypto-key No key or IV written into the source 321, 329 A04 manual recommended
sec-js/no-biased-random No byte taken modulo a number that does not divide 256 327 A04 suggest recommended
sec-js/no-insecure-random No Math.random for a token, a secret or a password 338 A04 suggest recommended
sec-js/password-hash-effort A password is stored with a slow, salted hash 916 A04 manual recommended
sec-js/no-hardcoded-secret No secret written into the source 798 A07 manual recommended
sec-js/timing-safe-compare A token, hash or signature is compared in constant time 208 A07 suggest strict
sec-js/jwt-verify A JWT is verified with a named algorithm, never none 347 A07 manual recommended
sec-js/no-secret-in-log No password, token or secret written to a log 532 A09 manual strict
sec-js/no-llm-output-to-sink No model output run, written as HTML or used as SQL 94, 79 A05 manual recommended
sec-js/no-prompt-injection No request data in a model's system prompt 1427 A05 manual recommended

How the rules know a value comes from a request

Several rules ask whether a sink's argument comes from a request (sec-js/no-path-traversal, no-ssrf, no-open-redirect, no-ssti, no-header-injection, no-log-injection, no-format-string, no-unvalidated-dynamic-method, no-prototype-pollution, no-llm-output-to-sink, no-prompt-injection). They use the from_source: predicate (SR-RULE-FORMAT decision 3a). It holds when the argument is a listed request source (or a method called on one), is built from one by concatenation, interpolation or ?:, or is a local name bound to one in the same function, one or more assignments or destructurings away. The sources are in this pack's data/sources/:

table sources
sources/express req.body, req.query, req.params, req.headers, req.cookies, req.url, … and the same on request (Fastify, Hapi)
sources/koa ctx.request.body, ctx.query, ctx.params, ctx.headers, ctx.cookies.get, …
sources/nextjs searchParams, request.nextUrl.searchParams, request.json, request.formData, …
sources/browser location.hash, location.search, document.referrer, window.name, document.cookie, event.data, …
sources/llm completion.choices, response.content, message.content, result.text, … (a model SDK's answer)

from_source: is not taint analysis. It never follows a call (a value passed through any function, a sanitizer or not, stops being a source), a return value, a parameter, a closure's outer variable or another file. A rule page that uses it says so. Rules that need to see more than one argument position (path.join(a, b)) look for a request path in the whole call instead. Every other rule fires on a dangerous sink with a value that is not a literal, or on a setting that is unsafe in itself.

What the rules are not

  • Not a scanner for the whole program. They read one file at a time and one function at a time; a value that crosses a function boundary is not seen.
  • Not a proof of safety. A clean run means no known-bad shape was found, not that the code is safe. strict rules are heuristics and warn.
  • Not for generated code or tests without care. Turn rules off for a folder with an [[overrides]] entry in codelaw.toml; sec-js/no-hardcoded-secret and sec-js/no-insecure-random fire in test helpers too.
  • Deviations from the first catalogue (W-54). sec-js/no-cleartext-http is manual: an edit primitive cannot rewrite the text inside a URL. sec-js/no-bidi-characters is suggest, not auto: only a comment is removed whole, and a string or regular expression with a hidden character is left for you. sec-js/no-prototype-pollution does not flag a literal .__proto__ write, only a request value used as a key or merged; sec-js/no-javascript-url reads the address by its text (location.hash, document.referrer, …), not through a local name.

Not ported, and why

eslint-plugin-security (Apache-2.0) is the source of the rules whose ported_from: names it; this table covers each of its rules. Bandit (Apache-2.0) and Ruff's S rules (MIT) are named in ported_from: the same way.

eslint-plugin-security rule here why
detect-buffer-noassert sec-js/no-new-buffer the noAssert argument is flagged there
detect-child-process sec-js/no-child-process-shell narrowed: a literal command is fine; shell: true is flagged
detect-disable-mustache-escape not ported the escapeMarkup = false switch is of one old template engine; the XSS it allows is flagged where the output is written (no-unsanitized-html, no-ssti)
detect-eval-with-expression sec-js/no-eval widened to new Function and string timers
detect-new-buffer sec-js/no-new-buffer with a suggested fix
detect-no-csrf-before-method-override sec-js/no-csrf-before-method-override with a suggested reorder
detect-non-literal-fs-filename sec-js/no-path-traversal (a request value), sec-js/no-non-literal-fs-filename (strict) split: the first is precise, the second is the original's breadth
detect-non-literal-regexp sec-js/no-unsafe-regex only a pattern built from a request is flagged
detect-non-literal-require sec-js/no-non-literal-require
detect-object-injection sec-js/no-unvalidated-dynamic-method, sec-js/no-prototype-pollution not ported as written: it flags every obj[key], which is most code; only a key a request supplies is flagged
detect-possible-timing-attacks sec-js/timing-safe-compare (strict) limited to names that hold a secret, with a suggested fix
detect-pseudoRandomBytes sec-js/no-insecure-random folded in
detect-unsafe-regex sec-js/no-unsafe-regex nested quantifiers in a regular expression literal
detect-bidi-characters sec-js/no-bidi-characters

Read for ideas only, never copied (L2): CodeQL's JavaScript queries (MIT), the OWASP cheat sheets, and — under licences that forbid copying — eslint-plugin-no-unsanitized (MPL-2.0), njsscan (LGPL-3.0) and Semgrep's rules (the Semgrep Rules License).

Metadata

Release files for codelaw-rules-security-js 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for codelaw-rules-security-js 0.4.3
File Interpreter ABI Platform Actions
codelaw_rules_security_js-0.4.3-py3-none-any.whl Python 3 none any Details for codelaw_rules_security_js-0.4.3-py3-none-any.whl

Release files / codelaw_rules_security_js-0.4.3-py3-none-any.whl

Download URL codelaw_rules_security_js-0.4.3-py3-none-any.whl
Size 128.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b607d9deefec2f7a7c5bcc8d4324f3c2335ec5599caacef90c5f61dcf835e793
BLAKE2b-256 checksum
How to use checksums
aee39c8a6c75d7bd9b79af2d9672b121d7ddf97bbb02d1aa5c2b8dc51e3f6598
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Security for codelaw-rules-security-js 0.4.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

1 file in this release has been uploaded with provenance metadata.

Attestation for codelaw_rules_security_js-0.4.3-py3-none-any.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page