Library / SDK
bitwiseshiftleft/sjcl avatar
bitwiseshiftleft/sjcl

sjcl: the deprecated Stanford Javascript Crypto Library and what the 1.0.9 ECDH fix changes

[DEPRECATED] Stanford Javascript Crypto Library

7,197 stars994 forksJavaScriptNOASSERTION

At a glance

What is it?
sjcl is marked deprecated in its own README, yet a 2026 ECDH vulnerability fix landed in version 1.0.9. Here is what the library does, how it is assembled, and why new projects should look elsewhere.
Who is it for?
Use sjcl only to keep an existing deployment running, and only after confirming it is on 1.0.9 or later, since earlier versions expose the ECDH key recovery bug described in the README. New projects should not adopt it: the README itself asks readers to consider a more modern alternative.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What sjcl solves, and the audience it was written for

sjcl is a cryptography library written in JavaScript and intended to run in a browser without a native crypto backend. The package.json browser field sets crypto to false, which tells bundlers not to pull in a Node crypto shim. Everything the library needs is implemented in JavaScript itself.

The audience is narrow now. It is for people maintaining a page or a Node script that already imports sjcl, and for readers trying to understand a historical design where a single script file carried AES, ECC, HMAC and several codecs. The README opens with a deprecation notice and states that the project has not been updated in many years except to fix one serious vulnerability. It then asks readers not to use it in new projects. That sentence is the most important line on the page, and it comes from the maintainers rather than from a third party.

How the library is assembled and how data moves through it

The repository does not ship a hand-maintained bundle. The Makefile concatenates a SOURCES list into core.js, and sjcl.js is produced by copying a compressed target into place. The compress directory holds scripts for Closure and YUI, so the same source tree can be compressed by either tool. A compression_stats target builds both and reports byte counts for core.js, core_closure.js and core_yui.js plus their gzipped sizes.

At runtime the modules are grouped by purpose. Cipher modes appear as separate test vector files for ccm, cbc, ctr and gcm; hashing appears through hmac vectors; public key work sits in the ecc, ecdsa and ecdh tests. The codec layer sits underneath all of it, converting between bit arrays and text or byte formats. That layering is why the 1.0.3 to 1.0.4 upgrade note matters: base32 output changed to match RFC 4648, padding with = became the default, and the old extended hex alphabet moved to sjcl.codec.base32hex. Data encoded before that release must now be decoded with base32hex, not base32. This is a silent format change for anyone who stored base32 output.

Installing sjcl and running the test suite from the Makefile

The package name is sjcl and the entry point is sjcl.js, so a CommonJS require returns the library object directly. The repository's package.json defines the npm scripts, and the Makefile carries the build and test targets. The commands below are the ones present in those two files.

bash
npm install sjcl
bash
npm test
bash
make test

The package.json test script runs make test, and the Makefile declares a test target alongside test_yui, test_closure and test_uncompressed, so the same vector files can be run against the uncompressed and compressed builds. The lint target runs eslint through npm run lint. The README does not document an install command or a first-use example; it points readers to the hosted documentation at bitwiseshiftleft.github.io/sjcl/doc/ and to the demo directory, which contains index.html, example.js, form.js and example.css. The README does not describe what those demo files do.

The 1.0.9 ECDH fix and the failure mode it closes

The README lists a security advisory dated 03.08.2026. According to the linked gist, sjcl is vulnerable because sjcl.ecc.basicKey.publicKey() does not validate that a point lies on the curve. An attacker who can supply crafted off-curve public keys and observe ECDH outputs can recover a victim's private key. The advisory singles out dhJavaEc(), which returns the raw x-coordinate of the scalar multiplication with no hashing, giving a plaintext oracle that does not need decryption feedback. The README states the bug is fixed in SJCL 1.0.9, and package.json carries version 1.0.9.

This is the case where sjcl is the wrong tool. Any protocol that accepts an ECC public key from an untrusted peer and feeds it into ECDH is exposed on versions before 1.0.9. If your design cannot guarantee that every public key arrives from a trusted source, the library's own advisory says the fix is an upgrade, not a configuration change. The README does not describe a workaround for older versions.

What to use instead, and where the approaches diverge

The README says to consider a more modern alternative but does not name one, so the comparison has to be made on architecture rather than on a specific package. The difference is where the primitives come from. sjcl implements AES, big number arithmetic, ECC and the cipher modes in JavaScript, which is why the Makefile has to concatenate and compress a source list at all. A modern alternative in the same position would delegate to the platform: the Web Crypto API in browsers, or the crypto module in Node. That removes the JavaScript big number code path entirely and puts the constant-time behaviour in the hands of the runtime rather than the library.

The trade-off is real. Platform crypto is asynchronous in the browser and does not cover every mode or curve that sjcl exposes, so code that relies on a specific sjcl mode cannot be swapped out mechanically. The 1.0.3 to 1.0.4 base32 change is a good illustration of the cost of staying: a format decision inside the library forced a migration on every consumer who had persisted encoded data.

Maintenance, licensing and upgrade cost

The repository is not archived, and the last push was on 2026-03-18. That push followed the 2026 advisory, so the recent activity is a security fix rather than ongoing development. The README's own deprecation paragraph is the clearest statement of maintenance intent, and it says the project has not been updated in many years. The most recent release listed is 1.0.8 from 2018-11-10, while package.json carries 1.0.9, so the version in the tree is ahead of the last tagged release named in the release list.

Licensing is dual: package.json declares (BSD-2-Clause OR GPL-2.0-only), and LICENSE.txt is the file to read for the exact terms. The OR means a consumer picks one of the two, and the GPL option carries obligations that the BSD option does not. That choice belongs with whoever handles your distribution, not with this article. Upgrade cost is concentrated in two places: the base32 alphabet move from 1.0.3 to 1.0.4, and the ECDH fix in 1.0.9. The README documents the first in detail and the second only as an advisory plus a version number.

Editorial conclusion

Use sjcl only to keep an existing deployment running, and only after confirming it is on 1.0.9 or later, since earlier versions expose the ECDH key recovery bug described in the README. New projects should not adopt it: the README itself asks readers to consider a more modern alternative. Before upgrading anything, check whether your code calls dhJavaEc() or passes externally supplied ECC public keys, because those are the paths the advisory implicates.

Frequently asked questions

Is sjcl still maintained?

The README states that sjcl is deprecated and asks readers not to use it in new projects. The repository is not archived and the last push was on 2026-03-18, but the README describes that activity as fixing one serious vulnerability rather than ongoing development.

How do I install sjcl from npm?

The package is named sjcl and its main entry point is sjcl.js, so npm install sjcl followed by require('sjcl') gives you the library object. The README points to the hosted documentation for usage rather than showing an install command.

Which sjcl version fixes the ECDH vulnerability?

The README advisory dated 03.08.2026 states the missing point-on-curve validation in sjcl.ecc.basicKey.publicKey() is fixed in SJCL 1.0.9, and package.json carries version 1.0.9. The advisory does not describe a workaround for earlier versions.

What changed in the sjcl 1.0.3 to 1.0.4 upgrade?

The README upgrade guide says codecBase32 was re-enabled to conform to RFC 4648, with = padding now applied by fromBits unless a truthy second argument disables it. The encoding alphabet changed, and the former extended hex alphabet moved to sjcl.codec.base32hex, so data encoded with the old base32 must be decoded with base32hex.

What licence does sjcl use?

package.json declares the licence as (BSD-2-Clause OR GPL-2.0-only), and LICENSE.txt holds the full text. The OR means a consumer chooses one of the two options, and the GPL option carries different distribution obligations than the BSD option.

Official sources

  1. bitwiseshiftleft/sjcl on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bitwiseshiftleft-sjcl.svg)](https://hysenlabs.com/projects/bitwiseshiftleft-sjcl)