Notes for add-on reviewers
MagiClip 0.7.0 · magiclip@magiclip.local · distributed unlisted to organisations through Firefox enterprise policy.
What it does
Caseworkers start a case from one or more forms in their organisation’s forms library. They clip values from approved casework pages, review where sources agree and conflict, and fill target forms with the checked values. All application logic runs inside the extension. The optional AI features go only to the organisation’s own gateway, and only after the user has approved a redaction preview of the exact request.
No remotely hosted code
- Every script that runs is in the package. There is no
eval,new FunctionorinnerHTMLin MagiClip’s own code, and the CSP forbids'unsafe-eval'. - The forms library (
lib/library-sync.js,lib/library.js) downloads JSON only. It is checked against a manifest with a SHA-256 per file and validated as untrusted input. Profiles are a declarative extraction language, whichlib/extract.jsinterprets with DOM queries. Detection patterns inprivacy.jsonare compiled withnew RegExp. Nothing from the library is executed as code. - Model weights for the on-device privacy model (Transformers.js plus ONNX Runtime WASM, in
privacy/worker.js) are data, not code. By default they come from Hugging Face:openai/privacy-filter, pinned to commit7ffa9a043d54d1be65afb281eddf0ffbe629385b. The SHA-256 of every file is built into the extension (DEFAULT_MODELinlib/model-fetch.js), and each download is checked as it streams. A request outside the model server, or for a file with no expected hash, is refused. The user can choose another server with the same files (Privacy tab), and policy can lock the address. Either way the pinned revision and hashes still apply unless policy sets others. Files are fetched with CORS, which Hugging Face allows, so no host permission is needed. - Prompts are packaged Markdown files in
prompts/. - Tesseract runs with
workerBlobURL: false, and its worker, core and language data are all loaded fromvendor/, never from a CDN.
Content security policy
script-src 'self' 'wasm-unsafe-eval'; object-src 'none'; img-src 'self' data: blob:;
frame-src 'none'; media-src 'none'; style-src 'self' 'unsafe-inline'
'wasm-unsafe-eval'is required to instantiate the packaged WebAssembly: ONNX Runtime for the privacy model, and tesseract.js-core for OCR.img-src data: blob:displays pictures and PDF pages the user drops into the reader, after they are rendered on the computer.
Permissions
| Permission | Why |
|---|---|
storage, unlimitedStorage | The active case, activity log, settings, profile drafts and the last good library copy are kept locally. The privacy model is cached locally with the Cache API, and can exceed the default quota. |
scripting | Injects the packaged in-page agent (lib/extract.js, lib/capture.js, lib/agent.js) into a casework tab when the user clips, picks a field or fills a form. |
tabs | Matches the current tab’s address against the library’s approved page profiles, follows tab changes for the activity log (approved systems only), and opens the full case, library, log and readiness pages. |
clipboardWrite | The user’s “Copy” buttons: values, the fill report, diagnostics. |
downloads | The user’s downloads of the activity log (CSV/JSON), settings and drafts backups, and exported profiles. |
| Host permissions | The organisation’s casework systems, forms library and AI gateway. The model server (Hugging Face by default) is fetched with CORS and needs none. |
<all_urls> (optional) | Only for organisations that grant it by policy, so that newly approved systems work without a new release. It is never requested in normal use. |
Data collection
MagiClip declares its data categories in data_collection_permissions. Case data is stored locally and deleted when the case ends. The only transmissions are to the organisation-configured forms library and AI gateway, and model-file downloads from the model server (Hugging Face by default), which carry no user data. See the privacy policy. Every AI request passes through previewBeforeSend() in lib/ai/boundary.js, and lib/ai/client.js refuses any payload that has not been approved. There is no analytics or telemetry, and nothing is sent to the publisher.
Third-party libraries
All are unmodified files from official npm releases, copied into vendor/ by tools/vendor.mjs. The same list ships in the package as vendor/SOURCES.tsv. Each checksum can be checked against the linked file:
curl -sL <url> | sha256sum
| File | npm release | SHA-256 |
|---|---|---|
vendor/transformers.min.js | @huggingface/transformers@4.3.1/dist/transformers.min.js | 8d6716d9086f57c30a4bf367dba61b887593573c770c454465e8019b2703e743 |
vendor/ort-wasm-simd-threaded.asyncify.mjs | onnxruntime-web@1.31.0-dev.20260914-8d85527a0/dist/ort-wasm-simd-threaded.asyncify.mjs | 0966b6105cd936744498aa60df7a22cbd47af3374dbc64a9ab561c08a71e3611 |
vendor/ort-wasm-simd-threaded.asyncify.wasm | onnxruntime-web@1.31.0-dev.20260914-8d85527a0/dist/ort-wasm-simd-threaded.asyncify.wasm | 49871f5a4409519797e127440868a6d1923339d9185907f301a5b2a1d90af082 |
vendor/pdfjs/pdf.min.mjs | pdfjs-dist@4.10.38/legacy/build/pdf.min.mjs | 44ec6f011027ee77791386b66c14876a5fc29e20bf0433c07c6726fff7212b72 |
vendor/pdfjs/pdf.worker.min.mjs | pdfjs-dist@4.10.38/legacy/build/pdf.worker.min.mjs | bd88805178a26c729db8c0107a5b630cb900ec070f4d8c7529a3e45530afd41d |
vendor/tesseract/tesseract.esm.min.js | tesseract.js@5.1.1/dist/tesseract.esm.min.js | 2537be686335e4b2637e933cdc85a52dd80267a592689c1bd63235c8591540ae |
vendor/tesseract/worker.min.js | tesseract.js@5.1.1/dist/worker.min.js | aca1229639fc9907d86f96e825955a2b7c5716d17f3bc3acd71f9c7ab66181fc |
vendor/tesseract/tesseract-core-simd-lstm.wasm.js | tesseract.js-core@5.1.1/tesseract-core-simd-lstm.wasm.js | ce20eda9533cbed1e6c2b4276fbae1e0adc61b6754b5513084be601787b457cf |
vendor/tesseract/tesseract-core-simd-lstm.wasm | tesseract.js-core@5.1.1/tesseract-core-simd-lstm.wasm | 66b601224a0c4a8977bc9d92dd39841189f9ca22cc4122fcd7208cdb0961eeef |
vendor/tesseract/tesseract-core-simd-lstm.js | tesseract.js-core@5.1.1/tesseract-core-simd-lstm.js | 4135a3f6f1cccf3bc92058c1273c49bb4cff6356e1ba15d1b8b4e76e9890526b |
vendor/tesseract/tesseract-core-lstm.wasm.js | tesseract.js-core@5.1.1/tesseract-core-lstm.wasm.js | 8f04aa0cc81e7bde33f80e92fa01a7a665f0b4884d098acf5de9c7104a11dfaa |
vendor/tesseract/tesseract-core-lstm.wasm | tesseract.js-core@5.1.1/tesseract-core-lstm.wasm | 5db58ea4d1bd4256be81e8ae3b4fa226c4625dfba1850b1b3308dbf3700e9929 |
vendor/tesseract/tesseract-core-lstm.js | tesseract.js-core@5.1.1/tesseract-core-lstm.js | fc54a973687325599214294ec90ea9665309cbdf6ca727c43a64651f24e923f7 |
vendor/tessdata/eng.traineddata.gz | @tesseract.js-data/eng@1.0.0/4.0.0_best_int/eng.traineddata.gz | 45b4cb346724ac1774f1c36f42f182b887bcdb28ebe63e6fff90ac41f3fcff91 |
The linter’s DANGEROUS_EVAL and UNSAFE_VAR_ASSIGNMENT warnings are all inside these library files. None comes from MagiClip’s own code.
Rebuilding from source
The source archive uploaded with each version contains the full repository at the release commit. The build uses open-source tools only:
# Node.js 24.19.0, pnpm 11.3.0, on Linux, macOS or Windows
pnpm install --frozen-lockfile
pnpm build:ext # runs tools/vendor.mjs, then web-ext build
# output: dist/magiclip-0.7.0.zip, and the packaged tree is extension/
MagiClip’s own code in extension/ is not minified, bundled or transpiled. The build only copies in the vendored libraries listed above.
Trying it
The quickest way is the hosted demo: fictional casework pages and a forms library at https://magiclip.surprisingly.ltd/demo/. Try the demo walks through every feature step by step. In short:
- Open the sidebar. In Settings, enter the library address
https://magiclip.surprisingly.ltd/demo/library/, press Connect and allow access to the site. - On the Case tab, tick two forms and start a case.
- Open /demo/client-1042.html, press Allow on magiclip.surprisingly.ltd, then Clip this page. Clip the rent account (it produces a conflict) and client-2077 (a different person, which shows the identity warning).
- Open /demo/dhp.html and press Fill this form. The plan is shown before anything is filled, and MagiClip never submits.
Page and library access is asked for at run time, through the optional host permission, so the demo needs no extra permission in the manifest. The demo pages are static HTML and their forms only move between pages on this site. AI features need an organisation gateway, which the public demo doesn’t have. Without one, the preview still works and nothing is sent.
The same demo runs offline from the source archive with pnpm demo (library address http://localhost:8787/demo/library/). pnpm test runs the unit tests.