181 lines
10 KiB
Markdown
181 lines
10 KiB
Markdown
# Security model
|
|
|
|
## Trust boundary and local processing
|
|
|
|
Selected `.one`, `.onepkg`, and companion `.cab` files are untrusted. The main
|
|
thread validates the selection and combined size, reads the files into
|
|
`ArrayBuffer`s, and transfers them to a dedicated module worker. CAB entries
|
|
are extracted only into memory; archive paths are never written to the
|
|
filesystem.
|
|
|
|
The worker is a fault-containment and responsiveness boundary, not a security
|
|
sandbox. A successful open keeps its session alive for page/resource/export
|
|
requests. Clearing the file, choosing another file, or unmounting the app
|
|
terminates that worker; a failed open also terminates it. JavaScript garbage
|
|
collection does not promise immediate release or secure erasure.
|
|
|
|
The application does not:
|
|
|
|
- upload or transmit notebook bytes;
|
|
- use a notebook-processing application backend, upload proxy, telemetry,
|
|
analytics, remote fonts, or notebook-referenced external content fetching;
|
|
the optional same-origin Toolbox catalogue/manifest is application chrome
|
|
and receives no notebook data;
|
|
- persist source or derived content in LocalStorage, IndexedDB, Cache Storage,
|
|
cookies, or a service worker;
|
|
- execute notebook content or inject notebook HTML/SVG;
|
|
- use WebAssembly, a Rust runtime, or a native helper.
|
|
|
|
## Active parser defaults
|
|
|
|
The main thread accepts one `.one`, or one `.onepkg` plus its `.cab`
|
|
companions. It permits at most 256 selected parts, 512 MiB per file, and 512 MiB
|
|
combined before reading.
|
|
|
|
The OneStore parser applies these independent defaults per section/store:
|
|
|
|
| Resource | Default limit |
|
|
| ------------------------------------------------ | -------------------------: |
|
|
| Section bytes | 512 MiB |
|
|
| Transaction fragments / entries | 16,384 / 1,000,000 |
|
|
| File-node list fragments / nesting | 16,384 / 64 |
|
|
| File nodes | 1,000,000 |
|
|
| Objects | 500,000 |
|
|
| Properties per set / property nesting | 16,384 / 64 |
|
|
| Stream IDs | 1,000,000 |
|
|
| FSSHTTPB revision-chain entries | 16,384 |
|
|
| One property vector | 64 MiB |
|
|
| Desktop object-reference vector | 1,000,000 per vector |
|
|
| FSSHTTPB ExGUID/CellID references | 1,000,000 aggregate |
|
|
| Nested PropertySets per ObjectPropSet | 1,000,000 aggregate |
|
|
| File-data objects / one payload / total payloads | 10,000 / 256 MiB / 512 MiB |
|
|
| Content-graph depth | 256 |
|
|
| Content blocks / text runs / table cells | 100,000 each |
|
|
| Decoded ink points | 100,000 |
|
|
| Pages | 10,000 |
|
|
| Diagnostics | 10,000 |
|
|
| Retained rich/extracted text | 2,000,000 UTF-16 units |
|
|
|
|
Images are automatically previewable only when a bounded PNG IHDR or JPEG
|
|
marker/SOF inspection succeeds. The compressed payload must be at most 32 MiB,
|
|
each dimension at most 16,384 pixels, and the image at most 67,108,864 pixels.
|
|
JPEG inspection reads at most 1 MiB of markers and 4,096 marker records. Images
|
|
outside those limits stay inert and are available only through an explicit
|
|
download action.
|
|
|
|
The CAB/package path applies these defaults across a complete cabinet set:
|
|
|
|
| Resource | Default limit |
|
|
| ------------------------------------------- | -----------------: |
|
|
| One cabinet / complete set input | 512 MiB / 512 MiB |
|
|
| Cabinet parts | 256 |
|
|
| Folder segments / files | 1,024 / 10,000 |
|
|
| CFDATA fragments | 131,072 |
|
|
| CAB name bytes | 255 |
|
|
| Path characters / path segments | 4,096 / 64 |
|
|
| TOC construction operations / diagnostics | 1,000,000 / 10,000 |
|
|
| One extracted file | 256 MiB |
|
|
| One logical folder output | 512 MiB |
|
|
| Total folder output / extracted entry bytes | 512 MiB / 512 MiB |
|
|
| Logical-folder compression ratio | 200:1 |
|
|
| One MSZIP compressed block | 32 KiB + 12 B |
|
|
| Quantum window | 2 MiB |
|
|
| LZX window | 8 MiB |
|
|
| LZX/Quantum decode operations | 1,000,000,000 |
|
|
|
|
A CFDATA block may declare at most 32 KiB of output. Counts and offsets use
|
|
checked arithmetic and bounded readers. The CAB parser verifies supplied block
|
|
checksums; rejects overlapping/out-of-range data, traversal/absolute/control or
|
|
case-insensitive duplicate paths; and validates a complete cabinet set before
|
|
decoding. Set IDs, indexes, links, compression, split blocks, and spanning-file
|
|
records must agree. Reserve areas are private to each cabinet/folder and are
|
|
validated locally rather than compared across parts.
|
|
|
|
MSZIP checks `CK` framing and raw DEFLATE data, writes into a fixed caller
|
|
buffer with overflow detection, requires the declared output size, and keeps at
|
|
most 32 KiB of logical-folder history. LZX and Quantum validate their windows,
|
|
trees/models, blocks/frames, matches, output, trailer, and operation budgets.
|
|
Codec state is preserved across continued cabinet segments. Extraction checks
|
|
cancellation between data blocks and periodically yields to the worker loop.
|
|
|
|
Desktop OneStore traversal checks fragment/reference cycles, nesting,
|
|
object/property/reference counts, and byte ranges. FSSHTTPB parsing bounds every
|
|
declared stream body and compact integer, rejects invalid end markers and
|
|
non-zero package tails, checks aggregate reference/mapping counts and revision
|
|
cycles, and retains BLOB payloads as bounded source ranges. Fragment records
|
|
are range-checked, but packages containing them are rejected because
|
|
fragmented-element reconstruction is not implemented.
|
|
|
|
## Display and export budgets
|
|
|
|
Parser DTOs are projected through a smaller page-display budget before React
|
|
creates nodes: 5,000 blocks, depth 64, 10,000 text runs, 500,000 displayed text
|
|
units, 2,000 table rows, 5,000 table cells, 256 columns, 10,000 ink strokes,
|
|
50,000 ink points, and 4,096 characters per metadata label. Exceeding a display
|
|
budget produces an explicit truncation notice. Newlines remain inside text
|
|
nodes instead of multiplying DOM elements.
|
|
|
|
Navigation and inspectors separately expose at most 250 page links, 500
|
|
notebook nodes at depth 16, 200 package entries per page, and 100 diagnostics
|
|
per page. Titles, previews, package paths, diagnostic fields, and panel labels
|
|
are length-bounded; pagination/truncation remains explicit in the UI.
|
|
|
|
Export planning independently permits at most 10,000 sections, 100,000 pages,
|
|
1,000,000 blocks, depth 256, 100,000 diagnostics, 8,000,000 text units, and
|
|
500,000 ink points. One resource and all resources are capped at 64 MiB; one
|
|
standalone output or all uncompressed static-ZIP members are capped at 128 MiB.
|
|
Planning accounts for metadata and projected UTF-8 output before serialization,
|
|
then verifies actual encoded/member sizes. Resource views remain zero-copy until
|
|
the bounded serializer needs bytes.
|
|
|
|
## Rendering, links, and downloads
|
|
|
|
DTO strings are rendered as React text nodes. Notebook HTML, scripts, active
|
|
SVG, and attachment payloads are never injected. Only parsed ink coordinates
|
|
generate application-owned SVG path attributes. Hyperlinks require an explicit
|
|
click, are limited to `http`, `https`, or `mailto`, and use
|
|
`rel="noopener noreferrer"`.
|
|
|
|
Automatic image requests carry a distinct preview intent. The worker rejects a
|
|
non-image, unapproved media type, unsafe dimensions, or oversized payload before
|
|
allocating/copying its bytes to the main thread. Approved image bytes may cross
|
|
for automatic preview; attachment bytes and rejected image bytes cross only
|
|
after the user presses a download button.
|
|
|
|
Static export HTML is inert, contains no script or external fetch, escapes all
|
|
text/attributes, embeds only images that pass the same inspector, and
|
|
neutralizes potentially active attachment suffixes. Exports represent the
|
|
supported reader model; they do not write OneNote files.
|
|
|
|
## Known gaps
|
|
|
|
- There is no wall-clock deadline. Synchronous OneStore graph parsing cannot
|
|
observe cancellation until control returns; terminating the worker is the
|
|
current hard stop.
|
|
- Package opening can hold source cabinets, decompressed logical folders,
|
|
extracted entry views, and parsed DTOs at overlapping times. Byte/count limits
|
|
bound them, but do not guarantee a low peak heap.
|
|
- Section content limits apply per contained section rather than once to the
|
|
complete `.onepkg`; cabinet/TOC limits are aggregate for the package set.
|
|
- CAB checksums detect accidental corruption but do not authenticate a package.
|
|
- Format coverage is limited to the documented golden files and structures.
|
|
New producer/version claims require licensed regression fixtures and malformed
|
|
variants.
|
|
- The worker boundary reduces UI impact but is not a substitute for browser and
|
|
operating-system isolation. Open especially sensitive files in a dedicated
|
|
browser profile if that risk matters.
|
|
|
|
Planned hardening includes elapsed-time budgets, more cancellation checkpoints,
|
|
lower-peak-memory extraction, expanded malformed-input/fuzz corpora, fragmented
|
|
FSSHTTP reconstruction, and additional licensed OneNote producer fixtures.
|
|
|
|
## Fixtures and vulnerability reporting
|
|
|
|
Never commit private notebooks. Fixture provenance and redistribution terms
|
|
must be recorded in `tests/fixtures/README.md`.
|
|
|
|
Report suspected parser vulnerabilities privately to the repository owner
|
|
through the Gitea instance before publishing malicious fixtures. Include the
|
|
application version, browser, smallest reproducible input, diagnostic, and
|
|
observed resource use. Do not attach sensitive notebooks.
|