src: throw on a malformed localStorage file - #65879
Draft
TrevorBurnham wants to merge 1 commit into
Draft
Conversation
Collaborator
|
Review requested:
|
The localStorage backing file is a user-specified path, and the schema is created with CREATE TABLE IF NOT EXISTS, so a file that already contains tables of those names is adopted as-is. Its stored values may then have any SQLite type, but every read asserted the expected type with CHECK, so a wrong-typed value aborted the process. A bad schema_version was the worst case: that assertion is in Storage::Open(), so any access aborted and the application had no chance to inspect or repair the file. Report these as ERR_INVALID_STATE instead, matching the throw four lines below the schema_version assertion for a version that is too new. Storage::GetAll() has no JavaScript caller to throw at, so it returns std::nullopt and the DOM storage inspector agent reports a protocol error. Also drop a redundant second sqlite3_exec() of the init SQL that clobbered the result of the sqlite3_prepare_v2() above it, hiding prepare failures behind a misleading "bad parameter or other API misuse". Signed-off-by: Trevor Burnham <trevorburnham@gmail.com> Assisted-by: Claude Opus 5
TrevorBurnham
force-pushed
the
webstorage-throw-on-malformed-file
branch
from
September 7, 2026 15:21
bc4a72b to
cfecc27
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes: #65878
src/node_webstorage.ccasserted the SQLite type of every column it read. But the backing file is a user-specified path, and the schema is created withCREATE TABLE IF NOT EXISTS, so a file that already contains tables of those names is adopted as-is and its values may have any type. Five of those assertions are reachable from crafted data, and each aborts the process. A wrong-typedschema_versionis the worst case: the assertion is inStorage::Open(), so any access aborts and the application cannot inspect or repair the file first.With this PR, the open now throws
ERR_INVALID_STATE:That matches what
Open()already does for a file written by a newer Node.js.Storage::GetAll()is the exception. Its only caller is the DOM Storage inspector agent, so there's no JavaScript caller to throw at. It returnsstd::nulloptinstead, andDOMStorageAgent::getDOMStorageItems()reports a protocol error.Storage::Length()keeps itsCHECK. Its query isSELECT count(*), which is always an integer, so it is not reachable through crafted data.This also drops a redundant second
sqlite3_exec()of the init SQL inOpen()that clobbered the result of thesqlite3_prepare_v2()five lines above it, so prepare failures went unreported: anodejs_webstorage_statetable with noschema_versioncolumn surfaced asbad parameter or other API misuse.Tests cover the four JavaScript-reachable sites in
test-webstorage.js, plus the inspector path in a newtest-inspector-dom-storage-malformed.js.One follow-up I left out of scope:
THROW_SQLITE_ERRORusessqlite3_errstr(code), so the prepare failure above now reportsSQL logic errorrather thanno such column: schema_version. Switching it tosqlite3_errmsg(db)would improve every throw in the file.