Imagine enforcing rules client-side. Now try to imagine someone doing that in javascript. Add to it the fact the code isn’t even obfuscated. And we’re talking about a platform that boasts a userbase of 20+ million.
Table of Contents
Open Table of Contents
But what on Earth is Unstop “SmartHire”
Unstop has a handy feature which allows quizzes and coding assessments for events to be conducted on Unstop itself, so the event organizers don’t have to worry about putting together their own infrastrcture.
Such quizzes are typically taken in the end-user’s browser. Obviously, browser APIs can’t detect software an average Joe would run to share their screen to cheat: take OBS Studio as an example. Unstop’s solution to this was to come up with a Desktop app, called SmartHire, that claims to “make sure an honest evaluation happens by preventing candidates from opening any unauthorized websites or downloading unauthorized apps/software while attempting the assessment”.
I learnt about it when a friend who had registered for one such event sent me a pic like so:
No Linux build ??
This friend had their Windows partition wiped upon unboxing their laptop, like any sane Linux user would. They sent me this pic asking how they could get it to work, because there is no download option for linux.
Lipstick on a Pig
I went ahead and registered for the assessment myself, and downloaded the Windows build: unstopsmarthire-1.0.17.exe
. It turned out to be a kernel-level anti cheat service a “Nullsoft Installer self-extracting archive” that could be unarchived using 7z
as-is.
Inside the extracted output were a bunch of standard Windows DLLs and an app-64.7z
. Upon extracting the app-64.7z
, we get to the meat of it:
app.asar
After npx asar unpack
ing app.asar, we find Unstop’s silly electron wrapper over its browser-based assessment software in all its glory.
Btw, in the extracted
app-64.7z
there exists a directory namedapp.asar.unpacked
. It contains nothing of interest and is probably either an artifact of packaging or an intentional red-herring 😂.
Getting the unpacked code to run
Copy over the preload.js
we extracted from the resources directory inside app-64.7z
, into the src
directory, where main.js
resides. Then change the getAppURL()
function inside src/utils/windowManager.js
to behave as if app.isPackaged
is true:
We can now run the app using npx electron .
. That should work everywhere electron runs, which includes (most) Linux. This fulfills our initial goal.
But can a dishonest party do more? Of course, they can.
How does SmartHire attempt to detect cheating?
The app registers IPC handlers on the electron browser window using preload.js
, and loads the same url (https://assessment-v1.unstop.com/ at the time of writing this) as the one used in web-based assessment. The presence of these handlers is what the website loaded from the url checks to distinguish a regular browser from the SmartHire app.
Obviously, each security check can be easily bypassed…
Carrot on a stick
For the specific case illustrated here, the quiz/coding-assessment round is a demo-round intended for users to gain familiarity, before the actual round is conducted. So playing around a little bit shouldn’t be a concern.
Let’s take the pig for a ride:
src/main.js
, let's first get auto-update out of our way

src/utils/displayManager.js

detectMirroring
simply return false in src/utils/displayUtils.js

src/utils/ipcHandlers.js

src/utils/systemUtils.js

That pretty much obliterates any edge in violation detection that SmartHire (a “desktop app”) has over the traditional browser based assessment.
Taking it further
Let’s open the floodgates: add the line mainWindow.webContents.openDevTools()
to the createMainWindow
function inside src/utils/windowManager.js
.
We now have the dev tools, and surprisingly, there is no debugger detection. It’d still look odd as the entire screen is being shared, so let’s fix that: Inside permissions.js
, replace desktopCapturer.getSources({ types: ["screen"] })
with desktopCapturer.getSources({ types: ["window"] })
. This won’t work just yet, because the browser-based part of the javascript has a check which requires the test-taker to share their entire screen. But now that we have dev-tools (undocked out into a separate window), let’s get this out of our way with local overrides:

There are a ton of other checks that can be bypassed this way. For instance, a dishonest candidate can search for and edit the declaration of the checkLiveliness
function to always return true
, effectively stopping Unstop from stopping the assessment when a pre-recorded video is fed through a virtual camera. Even doing so little as this easily gives any dishonest party a ticket to cheat freely without getting caught.
~Post()
By the way, Unstop now (by the time I got around to writing this post) also provides a download option for Linux, which obviously doesn’t change the situation a single bit because on unpacking, it’s the same as its Windows/mac counterparts.
If automated online assessments absolutely need to be relied upon, I’d say they should be best left to professional platforms made for the purpose. Unstop isn’t one of them, even remotely. To me, it looks like a pile of garbage with a cringe UI and a questionable privacy-policy that just so happened to have attracted enough unsuspecting users in its early days, that its use has become a societal requirement — kinda like the state of Wh🤢tsApp in India.