Security
Lens by Vectored · Last updated: August 2026
Threat model in one line. Lens runs on your machine and, as installed, has no network surface of its own, so the risks worth documenting are what it can reach locally and what it is trusted with. Connecting an AI provider adds one outbound path — to a company you chose, holding a key you supplied — covered in section 4.
1. Permissions, and why each one exists
A screen-capture extension necessarily asks for broad permissions. Here is what each is used for, so you can judge whether the trade is one you want to make.
| Permission | What it is used for |
|---|---|
| tabCapture | The video stream a GIF or MP4 recording is made from. Only for the tab you started recording on, and only while recording. |
| scripting | Injecting the selection overlay and editor into the tab at the moment you start a capture. Nothing is injected before that. |
| host_permissions for all sites | Required for the above to work on whichever page you choose to capture. It is not used to read pages in the background, and Lens has no code that does so. |
| tabs | Reading the active tab's title and URL to record alongside a capture, and bringing a recording's tab forward when you stop it from the popup. |
| activeTab | Capturing the visible area of the current tab for still screenshots. |
| downloads | The fallback path when no project folder is linked or access has lapsed. |
| storage | Settings, the project list and cached thumbnails. |
| offscreen | A hidden document that holds the recording stream, because a Manifest V3 service worker cannot. |
Lens requests no permission for native messaging, browsing history, cookies, bookmarks, the clipboard beyond an explicit copy you asked for, or identity.
The all-sites host permission above is what makes an outbound AI request technically possible once you configure a provider. No AI provider is configured by default, and Lens contacts no host on its own initiative — see section 4.
2. File system scope
Lens writes through the File System Access API, which is scoped by design:
- It can only touch folders picked by you in the browser's own picker. There is no path entry, and no way for the extension to name a folder you did not choose.
- A granted handle is stored in the extension's IndexedDB, but the grant itself is held by the browser and is revocable there.
- Re-granting lapsed access requires a click from you. The background service worker has no user activation and therefore cannot restore access on its own, by design of the platform — so silent re-acquisition is not possible.
3. No remote code
Everything Lens executes ships inside the extension package and is reviewable in the Chrome Web Store listing:
- No script is loaded from a CDN or any remote origin at runtime, which Manifest V3 forbids and Lens does not attempt.
- The GIF encoder is implemented in the extension rather than pulled from a third-party bundle, so there is no external package in the capture path.
- MP4 and WebM encoding is done by Chrome's own MediaRecorder, not by bundled codec code.
- The shutter sound is synthesised at runtime rather than shipped as an audio asset.
4. AI providers and key handling
AI features are off on install and there is no Vectored model, endpoint or proxy anywhere in the path. The AI features documentation covers setup and what each feature sends. When you enable them you pick who does the work — the browser's built-in model, a model on your own machine, or Claude or OpenAI with a key you supply. The first two keep everything on the device; the last two are an outbound request from your browser straight to that company.
Where the key lives, and why
- Requests to a keyed provider are made by the extension's background service worker, never by the code Lens injects into the page. Injected code shares a process with the page it is injected into, so a page-side compromise must not be able to read a key — it is never put there.
- The key is stored under its own storage area, separate from the settings the page-side code is allowed to read, so it cannot be picked up as a side effect of reading preferences.
- The settings screen writes keys but cannot read them back; it can only tell you whether one is saved.
- A key is sent to exactly one place: the provider it belongs to. It never reaches Vectored, and there is no Vectored endpoint for it to reach.
What is in a prompt
Only what the feature actually needs, and the amount differs by feature. The private-data check is the one that matters most: when a model is allowed to sharpen its results, it receives the type of each flagged region and the page title and heading — never the flagged text. A model is never asked to look at a credential to decide whether it is one.
Suggest name & description is the widest: it sends the text inside the captured region, because describing a screenshot is the task. It is a button you press per capture, never something that happens on save. Write steps from clicks sends only the accessible names of the controls that were clicked, never anything typed into a field, and works with no provider at all. Captured images are not sent to any provider.
Model output can only re-rank and relabel what the local rules already found. It can never add a region, and it can never blur one — blurring stays a click you make. A provider that is slow, unreachable or answers badly leaves the local results exactly as they were.
Model output is treated as untrusted
The page being captured is the same page whose title and headings go into the prompt that examines it. A hostile page can therefore write text aimed at the model — including text intended to talk it out of flagging that page's own credential fields. Lens is built on the assumption that this will be attempted:
- A high-confidence finding cannot be cleared by the model. A password field, or text matching a known key format, stays selected whatever the response says. The model can promote a lower-confidence finding but never demote a high one.
- A demoted finding is still shown. Nothing is ever removed from the list — at most it is left unticked, in front of you.
- Nothing generated is executed. Model output only ever becomes text in a field you can edit, or the order of a list. It is never run, never used to build a request, and never written to disk without passing through you.
- A suggested file name is sanitised like any other name Lens writes — extension stripped, path separators and filesystem-rejected characters replaced, length capped — so a name cannot direct a write outside your project folder.
The check that finds the regions in the first place runs on the page structure with no model involved, so with no provider configured none of this applies at all.
5. What Lens deliberately cannot capture
Some limits are Chrome's and are worth knowing, because they are security boundaries rather than bugs:
- Browser pages — chrome://, about:, the Web Store, DevTools, other extensions' pages — cannot be captured by any extension.
- DRM-protected video is excluded from tab capture by the platform and records as solid black. Lens detects this and warns rather than handing you a black file without explanation.
- file:// URLs require you to enable file access for the extension explicitly.
6. Handling sensitive captures
- Lens flags likely credentials in the captured region before you save and offers to blur them. That check runs on page structure in your browser, with no AI and no network call, and is on by default. Treat it as a safety net, not a guarantee — it looks for known shapes, so read the capture as well.
- Use the blur tool for anything the check missed. It rewrites pixels rather than covering them, so the original cannot be recovered from the saved file.
- Remember that a capture records the page URL and title into project_metadata.json. If the URL itself is sensitive — a signed link, a token in a query string — treat the metadata file with the same care as the image, or turn off Write metadata file in Settings.
- Point projects at a folder covered by whatever disk encryption and backup policy your captures warrant. Lens inherits the protection of the folder you choose and adds none of its own.
7. Reporting a vulnerability
If you find a security issue, please do not open a public issue or describe it in the support form. Email security@vectored.dev directly.
Useful things to include: the extension version, your Chrome version and platform, what an attacker would gain, and the smallest reproduction you can manage.
- We aim to acknowledge a report within three working days.
- We will tell you whether we consider it in scope, and why, rather than going silent.
- We will credit you in the release notes when a fix ships, unless you would rather we did not.
- Please give us a reasonable window to ship a fix before disclosing publicly.