Safeguard
Supply Chain Security•

Z-Wave Explained: Sub-GHz Mesh, S2 Security, SmartStart and Long Range

Z-Wave is a sub-GHz smart home protocol with a source routed mesh. How S2, SmartStart QR provisioning and Z-Wave Long Range work, and how to secure them.

Safeguard Security Team
35 min read

Z-Wave is a low power wireless protocol for home and light commercial control that runs in licence exempt sub-GHz bands (908.42 and 916 MHz in the US, the 868 MHz band in Europe) as a source routed mesh of up to 232 nodes. It is an open standard governed by the Z-Wave Alliance. A Z-Wave network is secure when every device joins with Security 2 (S2), the DSK is checked, legacy S0 is avoided and the controller is backed up.

This post sits next to our explainers on Zigbee, Thread and Matter, Home Assistant self hosting and how a smart lock is made. Here we stay on Z-Wave itself: history and governance, the radio and mesh, the network model, S2 and why S0 is legacy, SmartStart, Long Range, open source, and a lab with the open source Z-Wave JS driver.

Key takeaways

  • Z-Wave runs below 1 GHz, away from the crowded 2.4 GHz band. Its PHY, MAC, SAR and LLC layers are published as ITU-T Recommendation G.9959; the in force edition is G.9959 (01/15).
  • Classic Z-Wave is a source routed mesh of up to 232 nodes. The controller decides routes, and always listening devices relay frames.
  • The Z-Wave Alliance calls itself an independent, member driven Standards Development Organization. It publishes the specification twice a year (2026A is the current in force package) and runs certification.
  • S2 uses an elliptic curve Diffie Hellman (ECDH) key exchange on Curve25519, AES-128 in CCM mode for frames, and a Device Specific Key (DSK) with a 5 digit PIN to prove you are including the device in your hand.
  • S0 is legacy: weak key delivery and no device authentication. Grant it only to old devices that support nothing else.
  • SmartStart turns inclusion into a provisioning list: scan the QR code once, and the device joins itself with the classes you granted.
  • Z-Wave Long Range (ZWLR) adds a star topology with a 12 bit address space (up to 4,000 nodes), up to +30 dBm and only the two strongest S2 classes. It joins through SmartStart only and coexists with the mesh.
  • Back up the controller's non volatile memory (NVM), your keys and the provisioning list, or a dead USB stick means re-including every device.

Where did Z-Wave come from, and who governs it now?

Z-Wave began at Zensys, a Danish company building low cost wireless control for lighting and home automation, and later became part of Sigma Designs. For years its protocol lived inside one company's chips, which is why older articles call it proprietary. In April 2018 Silicon Labs completed its acquisition of the Sigma Designs Z-Wave business for $240 million, according to its own press release. The Z-Wave Alliance, formed in 2005 by a group of founding manufacturers according to its About page, ran interoperability certification throughout.

The radio layers had already been standardised by the ITU as G.9959, first published as G.9959 (02/12) and replaced by the edition approved on 13 January 2015, which added the SAR and LLC layers. The rest of the stack, including the network layer, security and the application command classes, now sits in a specification package the Alliance develops and publishes. The Alliance states that "Z-Wave is not proprietary" and that it is "an open standard governed by the independent, member-driven Z-Wave Alliance". Its specifications page says the package is updated twice a year (labelled xxxxA and xxxxB) and becomes "in-force" once implemented in the Certification Portal and the Compliance Test Tool (CTT).

The source code followed. In November 2022 the Alliance announced that the Z-Wave source code project was complete, with source and sample applications for members under the BSD 3 licence, contributions supervised by a new OS Work Group (OSWG), and quality enforced by a new mandatory Silicon and Stack certification. Its 2023 year in review reported 273 commits and more than 130,000 lines of changed code, plus work on a new security protocol version, Security S2 V2, and on Long Range frequencies for Europe.

Today the Alliance names three member silicon providers that build Z-Wave chips. A flaw in one stack therefore does not automatically sit in every Z-Wave product.

Timeline

DateEventSource
2005Founding manufacturers form the Z-Wave AllianceZ-Wave Alliance, About Us
February 2012ITU-T G.9959 (02/12), PHY and MAC layersITU-T G.9959 page
October 2013G.9959 Amendment 1ITU-T G.9959 page
13 January 2015G.9959 (01/15) adds SAR and LLC layers; in force todayITU-T G.9959 (01/15) page
18 April 2018Silicon Labs completes acquisition of the Sigma Designs Z-Wave businessSilicon Labs press release
September 2020Alliance announces the updated specification introducing Z-Wave Long RangeZ-Wave Alliance, ZWLR explainer
November 2022Source code project complete for members under BSD 3; OSWG formedZ-Wave Alliance announcement
December 2023Year in review: 273 commits; work on Security S2 V2 and EU Long Range frequenciesZ-Wave Alliance year in review
February 2025Alliance outlines 2024B: User Credential command class, CTT 3.9.1, EU Long Range moving to 864 and 866 MHzZ-Wave Alliance 2024B post
August 2025First Z-Wave Long Range end device for the EU announcedZ-Wave Alliance member news
20262026A is the in force specification packageZ-Wave Alliance specifications page

How does the Z-Wave radio work?

Z-Wave is a narrow band radio in the licence exempt short range device bands below 1 GHz. The ITU recommendation's title says it plainly: "Short range narrow-band digital radiocommunication transceivers". Each region has its own frequencies, which is why a European stick will not talk to a US lock.

Frequencies and data rates

G.9959 defines three data rates, R1, R2 and R3, and specifies FSK for R1 and R2, GFSK for R3, Manchester coding for R1 and NRZ for R2 and R3. The Alliance's Long Range explainer gives the US frequencies.

ModeData rateModulationUS frequency
R19.6 kbit/sFSK, Manchester coded908.42 MHz
R240 kbit/sFSK, NRZ908.42 MHz
R3100 kbit/sGFSK, NRZ916 MHz
Long Range100 kbit/sDSSS OQPSK912 and 920 MHz

In Europe, classic Z-Wave uses the 868 MHz short range device band, and the Alliance's 2024B-3 update shifts Long Range from 864.4 and 866.4 MHz to 864 and 866 MHz. The Z-Wave JS driver's region list also covers Australia and New Zealand, Hong Kong, India, Israel, Russia, China, Japan and Korea, with separate "USA (Long Range)" and "Europe (Long Range)" settings.

Why sub-GHz? Lower frequencies travel further for the same power and pass through walls better than 2.4 GHz. The cost is bandwidth: 100 kbit/s is plenty for "door opened" and useless for streaming.

What the band rules say

In the US, 47 CFR 15.249 covers low power intentional radiators in 902 to 928 MHz and limits the fundamental to 50 millivolts per metre field strength, with harmonics at 500 microvolts per metre. Higher power Long Range products rely on other parts of the FCC rules, and each product is certified individually.

In Europe, the harmonised standard for short range devices from 25 MHz to 1,000 MHz is ETSI EN 300 220-2, which sets duty cycle and power limits per sub-band; the ETSI archive lists v3.3.1 as its newest version. The Alliance says the 2024B-3 frequency change was made "ensuring compliance with new ETSI standards". Never import a controller or device for a different region: it may be illegal to operate, and it will not interoperate.

Source routed mesh, repeaters and node limits

Classic Z-Wave is a mesh, but not the kind where every node decides. G.9959 describes the network layer as "a source routing protocol" that "allows an originator to reach a destination node via one or more repeaters", with a reactive discovery algorithm to find new routes. The controller keeps a picture of which nodes hear which, computes routes and puts the route into the frame; each repeater forwards to the next listed hop.

Mains powered, always listening devices (plug in modules, wall switches) repeat. Battery devices usually sleep and wake on a schedule, or listen on a short duty cycle (G.9959 calls these frequently listening nodes), which is how a battery lock answers quickly. Sleeping devices do not route for others.

Consequences in the field:

  • Routes are only as good as the controller's knowledge. Move or unplug a repeater and frames follow stale routes until new ones are learned, so rebuilding routes after layout changes is normal maintenance.
  • Route length is limited, so a large property needs repeaters in the right places, or Long Range.
  • Routing is a security topic. A 2017 Computers and Security paper by Badenhop and colleagues, "The Z-Wave routing protocol and its security implications", analysed the routing layer. S2 protects the application payload end to end between controller and device, but routing and availability are a separate problem.

G.9959 states that each domain "may contain up to 232 nodes" and uses NodeIDs 1 to 232. The Alliance contrasts that 232 with the 4,000 nodes of Long Range.

What is the Z-Wave network model?

ElementWhat it isWhy it matters for security
Home IDA 32 bit network identifier (G.9959 calls it the HomeID)Separates your network from a neighbour's; not a secret, visible over the air
Node IDEach device's address (1 to 232 in the mesh; Long Range IDs start at 256 in Z-Wave JS)Assigned at inclusion; kept until exclusion
Primary controllerThe controller that created the network and assigns IDsHolds network keys and routing tables; the crown jewels
Secondary controllersA handheld remote or second gatewayEvery extra controller is another holder of keys
End devicesSensors, switches, locks, thermostatsEach is granted a set of security classes at inclusion
Command classesStandardised application messages, such as Binary Switch, Door Lock, Notification, Firmware Update Meta DataDefine what a device can do and what a controller can tell it

Inclusion and exclusion

Inclusion is how a device joins: put the controller into inclusion mode, then press a button on the device. The controller assigns a Node ID, and only then does security bootstrapping run. Z-Wave JS's documentation warns that "a common misconception is that an error causes the inclusion to be aborted"; the driver "only learns about a node after it was already included". A bootstrapping failure leaves the device in the network with lower security than you intended, unless you notice.

Exclusion is the reverse: the controller enters exclusion mode and the device is told to leave. Excluding a used device before including it is a common first step. A factory reset on the device alone leaves a dead entry on the old controller, which a "remove failed node" function cleans up.

Command classes and certification

A command class is a numbered set of commands for one function. The Alliance's specifications page says every device has a Device Type, a Role Type and a list of command classes, and the Certification Portal identifies the mandatory requirements. Because the application layer is standardised, a certified switch from one maker works with a certified controller from another. The 2024B package added a User Credential command class for access control, covering PIN codes, passwords, RFID, BLE, NFC, UWB and biometrics per user.

Two command classes matter for security: Security 2, which carries the S2 key exchange and the encrypted encapsulation, and Firmware Update Meta Data, which lets a controller push firmware images to a device over the air. That is a useful update path and one worth controlling.

How does S2 security work?

Security 2 replaced S0. Z-Wave JS's documentation says "modern Z-Wave devices are required to support Security S2" and recommends using it by default.

Security classes

S2 separates devices into classes, each with its own 16 byte network key, so a device holding only a lower key cannot read or forge traffic for a higher class.

ClassTypical devicesAuthentication at inclusionOn Long Range
S2 Access ControlDoor locks, garage door openersDSK checked with PINYes
S2 AuthenticatedSensors, sirens, lighting, thermostatsDSK checked with PINYes
S2 UnauthenticatedDevices with no printed PIN or QR codeNoneNo
S0 LegacyOlder locks and sensors without S2None, weak key exchangeNo
NoneNo security supportNot applicableNot applicable

Z-Wave JS takes four classic keys (securityKeys) and two Long Range keys (securityKeysLongRange), each exactly 16 bytes, and its Long Range guide says both LR classes "must use a different security key than their Z-Wave Classic counterparts". Generate every key separately.

The key exchange: ECDH on Curve25519

When a device joins with S2, controller and device each generate a key pair and run ECDH. The Z-Wave JS crypto code shows X25519 key handling, an ECDH shared secret fed into AES-CMAC based derivation of a temporary CCM key, and AES-128 CCM for encryption. Curve25519 and X25519 are specified in RFC 7748, published in January 2016 as an informational RFC representing the consensus of the IRTF Crypto Forum Research Group; X25519 takes and returns 32 byte strings.

The temporary key protects the rest of bootstrapping, over which the controller sends each granted network key. A passive listener who records the exchange cannot derive the keys, the core improvement over S0. But ECDH alone does not tell you who you are talking to: an active attacker in range could sit in the middle. That is what the DSK is for.

The DSK and the PIN

Every S2 device has a Device Specific Key printed on the device, packaging or manual, often with a QR code. Z-Wave JS writes it as eight groups of five digits: aaaaa-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222.

During authenticated inclusion the controller shows the DSK it received with the first five digits missing, and you type those digits, the PIN, from the label. If they match, the key in the exchange belongs to the device in your hand. Z-Wave JS requires applications to label that input "PIN", "since this is what's printed on devices users will have", and each dialog has a 240 second timeout before inclusion aborts. Only Access Control and Authenticated use this check; S2 Unauthenticated gets encryption but no proof of identity.

Frame encryption: AES-128 CCM and nonces

After bootstrapping, S2 encrypts and authenticates commands with AES-128 in CCM mode, so a tampered or forged frame fails verification. CCM needs nonces that never repeat under one key, so S2 nodes keep nonce state per peer, with separate key material for multicast (the Z-Wave JS code derives "MPAN" keys for this). After a reboot nodes resynchronise before continuing, and replayed frames fail. For operators this mostly appears as occasional nonce messages in debug logs.

What S2 does not protect

S2 protects the confidentiality and integrity of the application payload. It does not:

  • protect routing and topology information outside the encrypted payload;
  • stop radio jamming, which affects every licence exempt wireless system;
  • help devices included with S0 or no security; a network is only as strong as the weakest class you granted;
  • protect the controller host, its web UI, MQTT broker or cloud connection, where many real smart home compromises happen.

Academic work has looked at those edges: fuzzing Z-Wave devices for implementation flaws (VFuzz, IEEE Access, 2022), anomaly detection for attacks that use legacy devices or unencrypted frames (ZMAD, IEEE Access, 2023), and formal models of the protocol (Braghin, Lilli and Riccobene, Computers and Security, 2023). The common thread is that mixed networks, unencrypted fallbacks and device bugs leave room around the cryptography.

Why S0 is legacy

S0 was Z-Wave's first security layer. It used AES-128 and one network key for every secure device. As published security research describes it, the weakness was key delivery: the network key travels to the new device encrypted under a temporary key that is fixed and well known, so anyone who records an S0 inclusion can recover the network key. S0 also cannot authenticate the joining device, and it needs an extra round trip per nonce.

Z-Wave JS treats S0 bootstrapping in an S2 capable network as a warning sign: its S0Downgrade reason "indicates a possible downgrade attack and MUST be exposed to the user". The one honest reason to grant S0 is an old device that supports nothing better. Z-Wave JS notes that some devices advertise S2 but do not answer the key exchange, so its UI keeps a "use only S0" option. Use it deliberately, close to the controller, and once.

What do SmartStart and QR code provisioning change for installers?

SmartStart turns inclusion from a live, two handed event into data entry. You add the device to the controller's provisioning list in advance, with its DSK and the classes you grant. In Z-Wave JS's words, when a listed node "announces itself, it will automatically be included in the network within a couple of minutes". Scanning the QR code fills the entry in one step, including which protocols the device supports. For installers:

  • Devices can be provisioned before they are mounted and join when power comes on.
  • The DSK comes from the label, so authenticated S2 is the default rather than an extra step.
  • The provisioning list is data you can export and back up, which speeds replacement.

It also changes your risk. The list holds every device's DSK and granted classes, so treat it like a key list. Z-Wave JS notes that removing an entry for an already included node does not exclude it; exclude it separately.

What is Z-Wave Long Range, and how does it coexist with the mesh?

Z-Wave Long Range is an addition to the protocol, announced in September 2020, aimed at large homes, outbuildings, multi dwelling units and light commercial sites. From the Alliance's pages:

  • Topology: star. Each LR device talks directly to the controller. Z-Wave JS adds that LR nodes "cannot be used to route messages for non-ZWLR nodes".
  • Scale: a 12 bit address space and up to 4,000 nodes, against 232 for the mesh.
  • Radio: "an extra 100kbps DSSS OQPSK modulation" treated as an additional channel in gateway scanning, up to +30 dBm, and dynamic power control that adjusts output power on every transmission.
  • Range: the Alliance's LR page quotes a maximum of 1.5 miles at full power; its earlier explainer reported 1 mile (1.6 km) line of sight from the first implementation at +14 dBm. A 2025 EU product announcement claimed up to 1 km in open field. Treat all of these as best case.
  • Regions: the earlier explainer said LR was US only at the time; 2024B-3 set EU channels at 864 and 866 MHz, and the first EU LR end device was announced in August 2025.

One controller can run the mesh and an LR star together, and Z-Wave JS gives LR nodes IDs from 256 up. LR has only S2 Access Control and S2 Authenticated, with separate keys, and LR inclusion "works exclusively through Smart Start". Every LR device joins authenticated, with no S0 or unauthenticated fallback. Z-Wave JS says choosing LR should be "an opt-in rather than an opt-out", because the device will not be part of the mesh.

SituationMeshLong Range
Dense home with many mains powered switchesGood fit; switches strengthen the meshNot needed
Detached garage or gate far from the hubNeeds repeaters along the wayGood fit if both ends support LR
Very large site with hundreds of devicesLimited to 232 nodesUp to 4,000 nodes
Device must relay for othersYes (mains powered)No; LR nodes never route
Must include without a QR code or DSKPossible (S2 Unauthenticated, S0 or none)Not possible; SmartStart only

What open source exists, and who governs it?

The protocol stack. The Z-Wave source code project is available to Alliance members under BSD 3, supervised by the OSWG. The Alliance's announcement lists source for the mesh and Long Range network and upper MAC layers, sample applications, and a platform abstraction layer that lets members build lower MAC and PHY layers for their own silicon. The Alliance's public GitHub organisation also publishes BSD 3 repositories such as a stack Docker environment, a PC controller tool and Zniffer specifications. The specification itself is a downloadable package; 2026A is in force today.

The controller software. Z-Wave JS (the zwave-js npm package, from the MIT licensed zwave-js/zwave-js GitHub repository) describes itself as a "modern and standards-compliant Z-Wave device driver that runs almost anywhere". It talks to a USB controller over its serial API and implements S2, SmartStart, QR codes, Long Range, NVM backup and restore and firmware updates. It is a community project on GitHub, not governed by the Alliance.

From a supply chain point of view, the controller software is where most of your exposure sits. A hub running Z-Wave JS is a Node.js application with many transitive npm dependencies, often packaged as a container image, listening on a local web port. That is the part you can inventory and patch yourself.

How does Z-Wave compare with Zigbee, Thread with Matter and Bluetooth mesh?

Z-Wave (mesh)Z-Wave Long RangeZigbeeThread with MatterBluetooth mesh
BandSub-GHzSub-GHz LR channelsMostly 2.4 GHz2.4 GHz2.4 GHz
PHY basisITU-T G.9959Alliance LR PHY (DSSS OQPSK)IEEE 802.15.4IEEE 802.15.4Bluetooth Low Energy
TopologySource routed meshStarMesh with coordinator and routersIPv6 mesh with border routersManaged flooding mesh
Network size232 nodesUp to 4,000 nodesLargeLargeLarge
Join securityS2: ECDH Curve25519 plus DSK PINS2 via SmartStart onlyInstall codes or a well known trust centre key, by versionMatter commissioning with device attestationECDH provisioning, optional out of band authentication
Legacy weak modeS0, no securityNoneDefault link key in older profilesNone in MatterNo out of band authentication
GovernanceZ-Wave Alliance; ITU for lower layersZ-Wave AllianceConnectivity Standards AllianceThread Group; Matter by CSABluetooth SIG

Z-Wave's strengths are sub-GHz range, mandatory certification that makes interoperability predictable, and a mature application layer. Its weaknesses are lower data rates, regional radio variants and a network that is not IP native, so everything goes through a controller. That controller is your most important security boundary.

Step by step: include an S2 device with Z-Wave JS, verify its security class, back up the NVM

This lab uses Z-Wave JS directly from Node.js on a Linux host, with a Z-Wave USB controller for your region and one S2 device. In a home automation UI the same steps appear as dialogs.

1. Identify the controller by a stable path

Names like /dev/ttyUSB0 can change between boots. Use the stable by-id path and confirm it before anything writes to the controller.

# List stable serial paths; note the one that matches your Z-Wave stick
ls -l /dev/serial/by-id/

# Confirm which tty it points to and that nothing else is using it
readlink -f /dev/serial/by-id/usb-YOUR_STICK_ID
sudo fuser -v "$(readlink -f /dev/serial/by-id/usb-YOUR_STICK_ID)" || echo "port is free"

Stop any other software that holds the port. Two programs on one controller corrupt state.

2. Generate distinct keys and store them safely

You need six random 16 byte keys: four for the mesh classes and two for Long Range.

umask 077
mkdir -p ~/zwave-lab && cd ~/zwave-lab
for k in S0_Legacy S2_Unauthenticated S2_Authenticated S2_AccessControl LR_S2_Authenticated LR_S2_AccessControl; do
  printf '%s=%s\n' "$k" "$(openssl rand -hex 16)"
done > keys.env
chmod 600 keys.env
cat keys.env | cut -d= -f1   # print names only, never paste keys into chat or tickets

Back keys.env up encrypted and away from the controller. Lose the keys and the controller together, and every secure device must be included again.

3. Install the driver

npm init -y
npm i zwave-js
npm ls zwave-js     # record the exact version you installed

Pin the version in your lockfile. The driver and its dependencies are now part of your attack surface.

4. Start the driver with all keys and S2 callbacks

Create include.mjs. The callbacks are a minimal console version of the dialogs Z-Wave JS requires. It changes nothing until inclusion starts.

// include.mjs
import { Driver, InclusionStrategy, SecurityClass } from "zwave-js";
import { readFileSync, writeFileSync } from "node:fs";
import readline from "node:readline/promises";

const env = Object.fromEntries(
  readFileSync("keys.env", "utf8").trim().split("\n").map((l) => l.split("="))
);
const key = (n) => Buffer.from(env[n], "hex");
const port = process.argv[2]; // pass the /dev/serial/by-id/... path
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });

const driver = new Driver(port, {
  securityKeys: {
    S0_Legacy: key("S0_Legacy"),
    S2_Unauthenticated: key("S2_Unauthenticated"),
    S2_Authenticated: key("S2_Authenticated"),
    S2_AccessControl: key("S2_AccessControl"),
  },
  securityKeysLongRange: {
    S2_Authenticated: key("LR_S2_Authenticated"),
    S2_AccessControl: key("LR_S2_AccessControl"),
  },
});

driver.on("error", (e) => console.error(e));

driver.once("driver ready", async () => {
  console.log("Home ID:", driver.controller.homeId?.toString(16));
  for (const [id, node] of driver.controller.nodes) {
    const hi = node.getHighestSecurityClass();
    console.log(`node ${id}: highest class ${hi === undefined ? "unknown" : SecurityClass[hi]}`);
  }

  driver.controller.on("node added", (node, result) => {
    const hi = node.getHighestSecurityClass();
    console.log(`added node ${node.id}, highest class: ${hi === undefined ? "unknown" : SecurityClass[hi]}`);
    if (result.lowSecurity) {
      console.warn(`WARNING: lower security than intended, reason code ${result.lowSecurityReason}`);
    }
  });

  await driver.controller.beginInclusion({
    strategy: InclusionStrategy.Default,
    userCallbacks: {
      async grantSecurityClasses(requested) {
        console.log("Device requests:", requested.securityClasses.map((c) => SecurityClass[c]));
        const ans = await rl.question("Grant all requested S2 classes? (yes/no) ");
        return ans.trim() === "yes" ? requested : false;
      },
      async validateDSKAndEnterPIN(dsk) {
        console.log("DSK received (first 5 digits hidden):", dsk);
        const pin = await rl.question("Type the 5 digit PIN printed on the device label: ");
        return pin.trim();
      },
      abort() {
        console.log("Inclusion aborted");
      },
    },
  });
  console.log("Inclusion mode on. Press the device's inclusion button now.");
});

await driver.start();

Run it with the stable path you confirmed in step 1:

node include.mjs /dev/serial/by-id/usb-YOUR_STICK_ID

Compare the printed DSK with the label. If the groups after the PIN do not match exactly, press Ctrl+C: you are not talking to the device you think you are.

5. Verify the granted class

The script prints the node's highest class. For a lock expect S2_AccessControl; for a sensor or switch, usually S2_Authenticated. If you see S2_Unauthenticated, S0_Legacy or a lowSecurity warning, exclude the device, factory reset it, move it near the controller and include it again.

6. Back up the controller NVM

The controller's NVM holds the Home ID, node list and routes. Z-Wave JS reads it with backupNVMRaw; the radio is off during the backup, which takes several seconds up to a few minutes.

// backup.mjs (run with the same Driver options as include.mjs, after "driver ready")
const nvm = await driver.controller.backupNVMRaw((done, total) =>
  process.stdout.write(`\r${done}/${total} bytes`)
);
const name = `nvm-${driver.controller.homeId?.toString(16)}-${new Date().toISOString().slice(0, 10)}.bin`;
writeFileSync(name, nvm, { mode: 0o600 });
console.log(`\nSaved ${name}`);
await driver.destroy();
sha256sum nvm-*.bin > nvm-backups.sha256
gpg --symmetric --cipher-algo AES256 nvm-*.bin   # store the .gpg copy off the host

Warning: restoring an NVM overwrites the controller. Z-Wave JS warns that a failure during restore "may brick your controller". Before any restore, repeat the step 1 path check, prefer restoreNVM (which converts formats) over restoreNVMRaw, and keep the original backup until the restored network is tested.

7. Export the SmartStart provisioning list

driver.controller.getProvisioningEntries() returns the SmartStart provisioning list. Save it with the same permissions as keys.env and store it with your key backup.

8. Keep the software side current

npm outdated zwave-js
npm audit --omit=dev

Update the driver on a schedule and rebuild any container image that bundles it.

Common mistakes

  • Accepting S0 or no security when S2 was available. Some controllers fall back silently. Check the granted class after inclusion and treat an S0 grant on an S2 capable device as a possible downgrade.
  • Skipping the DSK check. Typing the PIN without comparing the rest of the DSK defeats authenticated inclusion.
  • Granting S2 Unauthenticated to everything. Use it only for devices with no printed DSK.
  • Reusing one key for several classes, or copying example keys from documentation. Generate every key separately, and keep Long Range keys apart from mesh keys.
  • No controller backup. A failed USB stick without an NVM backup and the keys means re-including every device, and possibly resetting locks by hand.
  • Buying devices for the wrong region. They will not talk to your controller and may break local radio rules.
  • Leaving old controllers and remotes in the network. Every secondary controller holds keys. Exclude what you no longer use.
  • Exposing the controller UI or WebSocket server beyond the local network. S2 does not protect the hub's web and API ports.

FAQ

Is Z-Wave proprietary?

Not any more. The Z-Wave Alliance, an independent, member driven Standards Development Organization, governs the specification and certification and states that Z-Wave "is not proprietary". The lower layers are ITU-T G.9959, and the protocol source code is available to Alliance members under BSD 3.

What frequency does Z-Wave use in the US and Europe?

In the US, classic Z-Wave uses 908.42 MHz (9.6 and 40 kbit/s) and 916 MHz (100 kbit/s), and Long Range uses 912 and 920 MHz. In Europe, classic Z-Wave uses the 868 MHz band and Long Range uses 864 and 866 MHz after the 2024B-3 update. Devices and controllers must match the region.

How many devices can a Z-Wave network have?

Up to 232 nodes in a classic mesh. Z-Wave Long Range raises this to up to 4,000 nodes through a 12 bit address space, and both can run on one controller.

Is Z-Wave S2 secure?

S2 uses ECDH on Curve25519, AES-128 CCM, separate keys per class and DSK PIN authentication, and no practical break of that cryptography is publicly known. Research has focused on what sits around it: routing, legacy or unencrypted devices on the same network, and device bugs. Use authenticated classes, avoid S0 and keep firmware and controller software updated.

What is the difference between S0 and S2?

S0 delivers one network key protected by a fixed, well known temporary key and cannot authenticate the joining device. S2 delivers per class keys over an ECDH protected channel and lets you authenticate the device with its DSK PIN.

What is the Z-Wave DSK, and where do I find it?

The Device Specific Key is printed on the device, packaging or manual, as eight groups of five digits, often with a QR code. The first five digits are the PIN you type during authenticated inclusion. Keep a record of it for re-inclusion.

How far can Z-Wave Long Range reach?

The Alliance quotes up to 1.5 miles at full power, and an earlier Alliance explainer reported 1 mile (1.6 km) line of sight at +14 dBm. Indoor range depends on walls, antenna placement and local rules.

How do I back up a Z-Wave network?

Back up the controller's NVM (in Z-Wave JS with backupNVMRaw, or your hub's backup function), the network keys and the SmartStart provisioning list. Encrypt them, store them off the controller host, and test a restore on spare hardware.

Where Safeguard fits

Safeguard does not monitor Z-Wave radio traffic, manage network keys, scan device firmware or include devices. The fit is the software around the radio. A controller built on Z-Wave JS is a Node.js application, often a container image, with a long tree of npm dependencies. Safeguard can scan that repository or image, list the components and versions inside, match them against vulnerability data, show which projects carry a given package version, apply policies and gates in CI, and open fix pull requests when you switch autonomous remediation on. Firmware on locks and sensors still has to be updated through each device maker's process.

A controller rebuilt after a failure pulls its dependencies again, and the driver, web UI and bridge services all ship open source components that receive fixes on their own schedule. That is why the next section still applies to a smart home radio protocol.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.

3. Gold Registry: start from components that are already fixed

Safeguard Gold rebuilds patched versions of open-source packages and images from source, signs each build, attaches an SBOM, SLSA provenance and VEX, and serves them from registry.safeguard.sh to your organization. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingSafeguard policies and gates in CI
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

These demos show dependency, SBOM and remediation workflows, not Z-Wave radio monitoring or device management. You can download Safeguard and follow the CLI docs to try them on your own projects.

This demo sets up the Safeguard runner on your own machine, approves it with its device code and scans from the terminal. Pointed at the container image or repository of a Z-Wave controller stack, the same scan lists the npm packages and versions inside and their known vulnerabilities, so you know what to rebuild after an advisory.

Click through it at your own pace, or open it full screen.

This demo is a real CLI session: you ask it to fix the lodash CVE in a repository, and it reads the finding and the advisory, asks before any command that changes something, moves lodash to 4.17.21, runs npm install and npm test with your approval, and pushes nothing. The same flow applies when a dependency of a Node.js hub or bridge service built on Z-Wave JS needs a version bump.

Click through it at your own pace, or open it full screen.

This demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. You can then ask which of your projects or images ship a given package version, such as a specific zwave-js release, and get the answer from your own scan data rather than from memory.

Click through it at your own pace, or open it full screen.

Quick check

You include a new S2 door lock and your controller reports the highest granted class as S0 Legacy, with a low security warning. What should you do?

Treat it as a failed secure inclusion and a possible downgrade. Exclude the lock, factory reset it, bring it close to the controller and include it again, checking the DSK and entering the PIN so it receives S2 Access Control. Only fall back to S0 deliberately, for a lock that genuinely cannot complete S2.

A detached garage is 400 metres from the house. You add a Z-Wave Long Range sensor there with SmartStart. Can it relay messages for a mesh switch in the garden?

No. Long Range is a star topology, so the LR sensor talks directly to the controller and does not route for classic mesh nodes. The garden switch needs a path through mains powered mesh devices, or it should be a Long Range device itself.

Sources

Last reviewed: 25 October 2026. The Z-Wave specification package is revised twice a year and Z-Wave JS releases often; check the pages above for the versions your controller and devices implement.

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.