Skip to content

Lock the Nexo crypto choices with ten node-security rules - #1759

Open
ofri-peretz wants to merge 2 commits into
Adyen:mainfrom
ofri-peretz:feat/node-security-crypto-rules
Open

Lock the Nexo crypto choices with ten node-security rules#1759
ofri-peretz wants to merge 2 commits into
Adyen:mainfrom
ofri-peretz:feat/node-security-crypto-rules

Conversation

@ofri-peretz

Copy link
Copy Markdown

src/security already does the right thing. This proposes making that
enforceable rather than conventional.

What is already correct here

  • nexoCrypto.ts:121timingSafeEqual behind an explicit length guard, with a
    comment explaining why the guard is there. That is the careful version; most
    code I read gets this wrong.
  • nexoCrypto.ts:107createHmac("sha256", …)
  • nexoCrypto.ts:98createCipheriv("aes-256-cbc", …) with an IV from
    randomBytes(NexoEnum.IV_LENGTH) (:112), not a constant
  • nexoCryptoPrimitives.ts:57 — the same timing-safe comparison

None of it is enforced by anything. A future edit can turn timingSafeEqual
into ===, or sha256 into sha1, and nothing in CI notices. That is the gap
this closes — it is a lock on decisions you have already made, not a change to
them.

The rules

Ten from eslint-plugin-node-security, chosen because each one maps to
something src/security actually does:

rule what it locks
no-timing-unsafe-compare the timingSafeEqual in validateHmac cannot become ===
no-weak-hash-algorithm HMAC stays on SHA-256
no-weak-cipher-algorithm no DES/RC4/Blowfish
no-deprecated-cipher-method no createCipher (keyless, IV-less)
no-ecb-mode CBC does not become ECB
no-static-iv the IV keeps coming from randomBytes
no-math-random-crypto key/nonce material never comes from Math.random()
no-insecure-rsa-padding no PKCS#1 v1.5 if RSA is ever added
require-aead-tag-verification if a GCM mode is added, the auth tag gets checked
no-dynamic-algorithm-selection the algorithm string stays a literal

Verification

  • npm run lint passes. No source file changes — the entire diff is
    .eslintrc.js, package.json and the lockfile.
  • Before opening this I ran the full plugin family (234 rules across ten
    security plugins) over src/229.5 KLOC, zero findings. This library is
    the cleanest scan in a 1,400-repository sweep I ran this week, which is why
    the ask here is "keep it that way" rather than "you have a bug".

The one override

src/__tests__/platforms.spec.ts:27 uses
Math.floor(Math.random() * Date.now()) to generate a throwaway account code.
That is fine, and it is not what no-math-random-crypto is aimed at — so the
rule is switched off for src/__tests__/**. Being straight about it: the rule
should default to allowing test files and does not yet, and I am fixing that
upstream. The override is here so this PR does not depend on that release.

Happy to trim the list to just the four that map to existing code
(no-timing-unsafe-compare, no-weak-hash-algorithm, no-ecb-mode,
no-static-iv) if the forward-looking six feel speculative.

@ofri-peretz
ofri-peretz requested a review from a team as a code owner August 23, 2026 19:36

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates the eslint-plugin-node-security ESLint plugin to enforce cryptographic and security rules, while adding an override to disable the no-math-random-crypto rule for test files. The feedback suggests restoring the trailing newline at the end of .eslintrc.js to adhere to best practices and prevent git diff warnings.

Comment thread .eslintrc.js Outdated
},
],
};
}; No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The trailing newline at the end of '.eslintrc.js' was removed. It is a best practice to keep a trailing newline at the end of all source files to ensure compatibility with POSIX tools and to avoid git diff warnings.

Suggested change
};
};

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8b0812f — thanks. The file ends with a newline again.

@gcatanese

Copy link
Copy Markdown
Contributor

Thank you @ofri-peretz for your contribution 🎉 We need to wait a little longer before we can merge this PR, we have a minimum 21 days age policy that doesn't allow us to merge newly released versions. I have marked the PR so we can assess again and merge later. Thank you!

@ofri-peretz

Copy link
Copy Markdown
Author

Thanks @gcatanese — a 21-day age policy is the right instinct for a payments SDK, and I would not want you to make an exception for this PR. I have worked out the exact dates so the wait is a scheduling question rather than an open one.

The PR currently pins eslint-plugin-node-security@^5.1.3, published 2026-08-23. Under a 21-day minimum that becomes eligible on 2026-09-13.

There is a shorter path if you would rather not hold the PR that long. 4.7.1 was published 2026-08-03, so it satisfies your policy today. It carries nine of the ten rules this PR enables — everything except require-aead-tag-verification, which was added in 5.0.0:

4.7.1 (eligible now) 5.1.3 (eligible 2026-09-13)
no-weak-hash-algorithm yes yes
no-weak-cipher-algorithm yes yes
no-deprecated-cipher-method yes yes
no-ecb-mode yes yes
no-static-iv yes yes
no-insecure-rsa-padding yes yes
no-dynamic-algorithm-selection yes yes
no-timing-unsafe-compare yes yes
no-math-random-crypto yes yes
require-aead-tag-verification no yes

For the Nexo path specifically, require-aead-tag-verification is the one that checks an AEAD decipher calls setAuthTag before final() — so dropping it is a real reduction in coverage, not a formality. Your call entirely: I am happy to re-pin to 4.7.1 now and follow up with a one-line bump once 5.x ages in, or to leave this as it is and let it clear on the 13th. Say the word and I will push whichever you prefer.

Two housekeeping notes in the meantime:

  • I have merged main into the branch — it was 12 commits behind, including the new documentCollector typings. npm run lint is still clean across the merged tree, so the rules have now seen a batch of new SDK code without producing a finding.
  • The trailing-newline nit from the review bot was fixed in 8b0812f.

No rush from my side, and no need to reply twice — I will keep the branch current either way.

ofri-peretz and others added 2 commits August 25, 2026 09:46
src/security already does the right thing: HMAC-SHA256, AES-256-CBC with a
randomBytes IV, and timingSafeEqual behind a length guard. None of that is
enforced by anything, so a future edit can weaken it silently.

Ten rules from eslint-plugin-node-security, all currently passing on src/.
No source change; one test override, since Math.random() generating a throwaway
account code in a spec file is not what no-math-random-crypto is aimed at.
Caught in review. POSIX tools expect a final newline and git flags its
absence on every subsequent diff of the file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ofri-peretz
ofri-peretz force-pushed the feat/node-security-crypto-rules branch from b571555 to a750356 Compare August 25, 2026 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants