Swift A11y: a note for IT and security reviewers
Swift A11y is a set of fifteen accessibility testing tools for quality assurance testers and developers. It comes as a browser extension for Chrome, Edge and Firefox, and as bookmarklets. This note says what it can and cannot do, so a review can be done in one sitting. Every claim below can be checked against the source and the built files, and the last section says how.
In one paragraph
The extension asks for two permissions: activeTab and scripting. It does nothing until a person presses its toolbar button and chooses a tool. It then runs that one tool on that one tab. The tool reads the page and draws its results in a panel of its own. It sends nothing anywhere, stores nothing, and never shows, stores or copies what anyone has typed or chosen in a form. It has no background script, no content script that runs on every page, no host permissions, no remote code and no analytics.
Permissions
| Permission | Why it is needed | What it allows, and what it does not |
|---|---|---|
activeTab | To run a tool on the tab the person is looking at, when they ask. | Access to the current tab only, only after the person presses the button, and only until that tab goes to another page. No access to other tabs, other windows or any site in the background. |
scripting | To put the chosen tool into that tab. | Used with activeTab, so it reaches only the tab the person chose. The scripts it runs are the fifteen tool files inside the extension package, never code from the internet. |
It does not ask for: host permissions (<all_urls> or any site), tabs, storage, cookies, history, downloads, webRequest, clipboardRead, debugger, nativeMessaging or any optional permission. Firefox's manifest declares that no data is collected (data_collection_permissions: none).
What it does on a page
- Reads: the page's structure (headings, landmarks, links, form labels, images, tables, colours, sizes and positions) to report what a screen reader would announce and what fails accessibility rules.
- Draws: a results panel and outlines on a separate layer inside a shadow root. It does not change the page's own layout, content or styles. Text Spacing is the one tool that applies a style while it is on, because that is the test (WCAG 1.4.12); it removes it when turned off.
- Turns off: choosing the same tool again removes everything it added and leaves the page as it was.
- Typed and chosen values: never shown, stored or copied. Text inside form fields, editable regions, select boxes and list boxes is left out of every name, row and copied result, including when a label or error message quotes it.
Network and storage
- No network requests from the extension, its popup or any tool: no analytics, no error reporting, no update checks of its own. Browser store updates are handled by the browser in the usual way.
- Nothing stored: no
localStorage,sessionStorage, IndexedDB, cookies or extension storage, on the page or in the extension. - The one link: each tool's panel has a small "Swift A11y" link to the project's website, and copied results end with one line naming it. These are plain links. Nothing is sent unless a person clicks the link, and then it is an ordinary page visit in a new tab. The address carries only the tool's name and the form, for example
?from=headings-extension, never anything about the page being tested. The browser's normal referrer rules apply, which by default share only the domain the person came from. - Copy: the Copy button writes the tool's results to the clipboard when a person presses it. Nothing is read from the clipboard.
Where it can and cannot run
It cannot run on browser pages (chrome://, edge://, about:), the browser's extension stores, or the built-in PDF viewer: browsers do not allow it, and the extension says so in a plain sentence. Local files need the browser's "Allow access to file URLs" switch, which is off by default.
The bookmarklets
The same fifteen tools are also offered as bookmarklets: a bookmark whose address is the tool itself. They follow the same rules: no network requests, nothing stored, nothing typed shown. A bookmarklet needs no installation and no permission, and runs only when the person clicks the bookmark. Sites with a strict Content Security Policy may refuse to run it; the extension is not affected by that.
How to check all of this
- The manifest:
manifest.jsonin the extension package lists the permissions above and nothing else. - The source: the tools are TypeScript in
src/, the extension's own code is inextension/src/. The project is open source under the MIT licence. - The built files: the package holds the popup, fifteen tool files and four icons. Each tool file is one self-contained script.
- The automated checks that run on every change include: the manifest asks only for
activeTabandscripting; there are no host permissions, content scripts, background script or remote pages; no tool or popup file contains a network call (fetch,XMLHttpRequest,WebSocket,sendBeacon), storage oreval; typed and chosen values never appear in a panel or in copied text; and each tool turns off leaving the page as it was. - By hand: open the browser's developer tools on the Network panel, run any tool, and see that no request is made.
Installing it for everyone
Each browser can install an extension for every user silently, and keep it updated, from the browser's own store. All three need the extension to be listed first, because the policies below name the extension by its store ID. Until then, the placeholders <CHROME-ID>, <EDGE-ID> and <FIREFOX-ID> stay in these steps. This note is also published at swifta11y.com/for-it-teams, so nobody needs a code-hosting site to read it.
- Chrome ID: 32 lower-case letters, shown in the Chrome Web Store address of the listing and at
chrome://extensionswith Developer mode on. - Edge ID: a different 32-letter ID, shown at the end of the address of the listing on the Microsoft Edge Add-ons website and at
edge://extensions. An Edge-listed extension does not share the Chrome ID. - Firefox ID: the
browser_specific_settings.gecko.idin the Firefoxmanifest.json. Today it is the placeholdera11y-tools-dev@a11y-tools.invalid. It changes before the first listing, because an add-on's ID cannot change after it is published. This note is updated with the real value then. Use<FIREFOX-ID>for it below.
After any change, open chrome://policy, edge://policy or about:policies on a test machine. The extension and its policy should be listed with status OK, and the toolbar button should be there without anyone installing anything.
Test on one machine, then a pilot group, before the whole company. Policy names are case sensitive.
Chrome
Policies and where they go (Chrome Enterprise policy list):
| Policy | Type | What it does |
|---|---|---|
ExtensionInstallForcelist | List of strings | Installs the extension silently and keeps it. Users cannot remove or disable it. Takes precedence over ExtensionInstallBlocklist. Each entry is the ID, optionally followed by ; and an update URL. With no update URL, the Chrome Web Store is used. |
ExtensionInstallAllowlist | List of strings | Exempts the listed IDs from ExtensionInstallBlocklist. Only needed if you block extensions in general (blocklist value *). It lets users install the extension; it does not install it. |
ExtensionSettings | Dictionary (JSON) | One policy that can do the same and more: install mode, toolbar pinning, blocked permissions. If it sets an extension, it overrides the two policies above for that extension. |
Windows, Group Policy (Active Directory): load Google's Chrome ADMX templates, then Computer Configuration, Administrative Templates, Google, Google Chrome, Extensions.
- "Configure the list of force-installed apps and extensions": Enabled, Show, one row per entry:
<CHROME-ID>;https://clients2.google.com/service/update2/crx - "Configure extension installation allow list" (only if you block by default): Enabled, Show, one row:
<CHROME-ID>
Windows, registry (same effect, for scripts or Intune custom settings), under HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome:
- Key
ExtensionInstallForcelist, a value named1of typeREG_SZwith the data<CHROME-ID>;https://clients2.google.com/service/update2/crx. Further extensions use2,3and so on. - Key
ExtensionInstallAllowlist, a value named1of typeREG_SZwith the data<CHROME-ID>. - Or, for
ExtensionSettings, aREG_SZvalue namedExtensionSettingson theChromekey holding the JSON below on one line.
macOS, configuration profile (Jamf, Intune, Kandji and similar): a custom settings payload for the preference domain com.google.Chrome:
<key>ExtensionInstallForcelist</key>
<array>
<string>CHROME-ID;https://clients2.google.com/service/update2/crx</string>
</array>
(Replace CHROME-ID with the real ID; the angle brackets are left out here because they would break the XML.)
The same payload can carry ExtensionInstallAllowlist (an array of IDs) or ExtensionSettings (a dictionary keyed by ID, with the fields below as strings).
Google Admin console (managed Chrome, cloud-managed):
- Sign in to the Admin console, then Devices, Chrome, Apps & extensions. With Chrome Browser Cloud Management it is Chrome browser, Apps & extensions.
- Choose Users & browsers, then the organisational unit (or a group) that should get it.
- Add the extension by its ID from the Chrome Web Store. (Add by ID is the yellow plus button at the bottom right. This step was not re-read from Google's page for this note; check it on screen.)
- Click the extension, and under Installation policy choose Force install. Click Save. (To pin it to the toolbar, use the Pin to browser toolbar choice, which writes
toolbar_pinbelow.) - To undo an override later, click Inherit.
ExtensionSettings (the modern, single policy), for Chrome:
{
"<CHROME-ID>": {
"installation_mode": "force_installed",
"update_url": "https://clients2.google.com/service/update2/crx",
"toolbar_pin": "force_pinned"
}
}
installation_mode is allowed (default), blocked, force_installed (installed, cannot be removed), normal_installed (installed, user may disable) or removed. The two install modes need update_url, and cannot be set on the * entry. toolbar_pin is default_unpinned (default), default_pinned or force_pinned. Use normal_installed and default_pinned if people should be able to switch it off.
Microsoft Edge
Edge uses the same policy names, set under Edge's own paths (Microsoft Edge policy documentation).
| Policy | Edge's caption |
|---|---|
ExtensionInstallForcelist | Control which extensions are installed silently |
ExtensionInstallAllowlist | Allow specific extensions to be installed |
ExtensionSettings | Configure extension management settings |
- Group Policy: load the Microsoft Edge ADMX templates. Administrative Templates, Microsoft Edge, Extensions, "Control which extensions are installed silently": Enabled, Show, one row per entry:
<EDGE-ID>;https://edge.microsoft.com/extensionwebstorebase/v1/crx. For the allow list the setting is "Allow specific extensions to be installed", and each row is<EDGE-ID>. Microsoft's note: the entry form isextension_id;update_url. - Registry: under
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge, a key per policy (ExtensionInstallForcelist,ExtensionInstallAllowlist) with numberedREG_SZvalues1,2, and so on, as for Chrome.ExtensionSettingsis oneREG_SZvalue holding the JSON on one line.HKEY_CURRENT_USERcan be used in place ofHKEY_LOCAL_MACHINE. The base key is stated in Microsoft's ExtensionSettings guide; the numbered-value layout for the two list policies is the standard Chromium layout and was not restated on the pages read. - macOS: a configuration profile (or
.plist) for the preference domaincom.microsoft.Edge, using the same policy names. Microsoft documents the steps for a plain.plistand for Jamf. The domain name was not restated on the pages read; check it against Microsoft's "Configure Microsoft Edge on macOS" page. - Edge management service / Intune: the same policies, set from the Microsoft 365 admin center or Intune's settings catalog.
ExtensionSettings for an extension listed on the Microsoft Edge Add-ons website:
{
"<EDGE-ID>": {
"installation_mode": "force_installed",
"update_url": "https://edge.microsoft.com/extensionwebstorebase/v1/crx",
"toolbar_state": "force_shown"
}
}
Edge's installation_mode values are allowed, blocked, force_installed, normal_installed and removed. toolbar_state (Edge 103 and later) is default_hidden, default_shown or force_shown. Microsoft says a force-installed extension cannot be disabled or removed by the user, and overrides any blocklist.
Installing from the Edge Add-ons store, one person at a time: open the listing on the Microsoft Edge Add-ons website (https://microsoftedge.microsoft.com/addons/), choose Get, then Add extension. Pin it from the puzzle-piece menu next to the address bar. Edge can also add extensions from the Chrome Web Store, and Microsoft's guidance lists both stores as places to audit an extension before approving it. For a managed fleet, prefer the Edge listing and the <EDGE-ID>, so the extension updates from the store your Edge policy already allows.
Firefox
Firefox calls these enterprise policies (Mozilla's policy reference). Two policies can install an add-on: Extensions (older, with Install, Uninstall and Locked lists) and ExtensionSettings. Mozilla recommends ExtensionSettings.
policies.json (any platform). The file holds { "policies": { ... } }. Put it in a distribution folder:
- Windows:
distribution\policies.jsonin the folder that holdsfirefox.exe. - macOS:
Firefox.app/Contents/Resources/distribution/policies.json. - Linux:
distribution/policies.jsonin the Firefox installation folder, or/etc/firefox/policies/policies.json.
{
"policies": {
"ExtensionSettings": {
"<FIREFOX-ID>": {
"installation_mode": "force_installed",
"install_url": "https://addons.mozilla.org/firefox/downloads/latest/<ADDON-SLUG>/latest.xpi"
}
}
}
}
installation_mode:allowed(default),blocked,force_installed(cannot be removed) ornormal_installed(users may disable it). The two install modes needinstall_url, unless the add-on is on addons.mozilla.org (Mozilla's page makesinstall_urloptional for those from Firefox 153).<ADDON-SLUG>is the last part of the listing's address on addons.mozilla.org. Thelatest.xpiaddress form was not restated on the pages read; check it by opening it in a browser.default_area:navbarputs the button on the toolbar,menupanelin the menu (Firefox 113 and later).private_browsing:trueallows it in private windows (Firefox 136 and later).- The
*entry may only beallowedorblocked. To block everything else, set"*": { "installation_mode": "blocked" }and add one entry per approved add-on. - The older form is
"Extensions": { "Install": ["<url>"], "Locked": ["<FIREFOX-ID>"] }. It takes the same file.
Windows Group Policy: load Mozilla's firefox.admx and firefox.adml from the policy-templates repository. ExtensionSettings is stored as a multi-line string value ExtensionSettings under HKEY_LOCAL_MACHINE\Software\Policies\Mozilla\Firefox, holding the JSON above without the outer policies key.
macOS: a configuration profile with an ExtensionSettings key holding a dictionary, an entry per ID, and installation_mode and install_url as strings. Mozilla publishes the profile template with the policy-templates.
Linux: policies.json as above; there are no registry or profile options.
Firefox shows the policies at about:policies. The first run installs the add-on when the browser starts and can reach install_url. The add-on's strict_min_version is Firefox 140.
What was not confirmed
- The real IDs, update addresses and slug do not exist until the listings do.
- The Google Admin console step "Add by ID", the Edge macOS preference domain, the
.../latest.xpiform and the numbered registry layout for the list policies were not restated on the pages read. Each is marked above; check it on a test machine withchrome://policy,edge://policyorabout:policies. - The vendors change these pages. Dates read: 14 October 2026.
Sources
- Chrome
ExtensionInstallForcelist(title "Configure the list of force-installed apps and extensions"; format, type and precedence from the policy definition in the Chromium source,components/policy/resources/templates/policy_definitions/Extensions/ExtensionInstallForcelist.yaml) - Chrome
ExtensionInstallAllowlist(andExtensionInstallAllowlist.yamlin the same folder of the Chromium source) - Chrome
ExtensionSettingsand support.google.com/chrome/a/answer/9867568 - Force-install in the Admin console
- Edge, force-install, allow and block
- Edge,
ExtensionSettingsfields, update URL and registry base key - Edge, policy names
- Edge, extension management overview
- Firefox
ExtensionSettings - Firefox
Extensions - Firefox policy files and templates and firefox-admin-docs.mozilla.org/guides/getting-started
Reporting a concern
Report a security or privacy problem through the support page of the project's website, swifta11y.com/support, which says how to do it privately. Nothing a reviewer needs is kept only on a code-hosting site.
Changes to this note
This note is updated in the same change as anything that alters a permission or adds a script. A planned screenshot feature will add a small background script to capture the visible tab, using the activeTab permission the extension already has; this note will say so when it ships.