Skip to content

src: throw on a malformed localStorage file - #65879

Draft
TrevorBurnham wants to merge 1 commit into
nodejs:mainfrom
TrevorBurnham:webstorage-throw-on-malformed-file
Draft

src: throw on a malformed localStorage file#65879
TrevorBurnham wants to merge 1 commit into
nodejs:mainfrom
TrevorBurnham:webstorage-throw-on-malformed-file

Conversation

@TrevorBurnham

@TrevorBurnham TrevorBurnham commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Fixes: #65878

src/node_webstorage.cc asserted the SQLite type of every column it read. But the 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 and its values may have any type. Five of those assertions are reachable from crafted data, and each aborts the process. A wrong-typed schema_version is the worst case: the assertion is in Storage::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:

$ node --localstorage-file=/tmp/ws.db -e "localStorage.length"
Error: localStorage database is malformed: expected schema_version to be an integer
  code: '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 returns std::nullopt instead, and DOMStorageAgent::getDOMStorageItems() reports a protocol error.

Storage::Length() keeps its CHECK. Its query is SELECT 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 in Open() that clobbered the result of the sqlite3_prepare_v2() five lines above it, so prepare failures went unreported: a nodejs_webstorage_state table with no schema_version column surfaced as bad parameter or other API misuse.

Tests cover the four JavaScript-reachable sites in test-webstorage.js, plus the inspector path in a new test-inspector-dom-storage-malformed.js.

One follow-up I left out of scope: THROW_SQLITE_ERROR uses sqlite3_errstr(code), so the prepare failure above now reports SQL logic error rather than no such column: schema_version. Switching it to sqlite3_errmsg(db) would improve every throw in the file.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/inspector

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Sep 7, 2026
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 TrevorBurnham changed the title webstorage: throw on a malformed backing file src: throw on a malformed localStorage file Sep 7, 2026
@TrevorBurnham
TrevorBurnham force-pushed the webstorage-throw-on-malformed-file branch from bc4a72b to cfecc27 Compare September 7, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

localStorage: a malformed backing file aborts the process via CHECK

2 participants