Responding to a Policy Violation Takedown
What to do when a live extension is disabled or removed for a policy violation — reading the notice, the appeal versus resubmit decision, restoring users, and preventing a repeat.
Table of Contents
A takedown is different from a rejection. A rejected submission never reached users; a takedown affects an extension people already have. Depending on the violation, the store may remove the listing, disable the extension on every installed browser, or mark it as malware — and each of those has a different path back. Speed matters, but the first response determines whether recovery takes days or ends the extension. This guide is part of store submission and permissions compliance.
What kind of action was taken
A warning with a deadline is by far the most common first contact, and it is the easiest to resolve — if the email is read. Route store notifications to an address that is monitored, not to the personal inbox of the developer who registered the account four years ago.
Step-by-step
1. Read the notice for the policy reference, not the tone
Enforcement emails are templated. The useful content is the policy section cited and, sometimes, a one-line description of the evidence. Map it to a specific part of the program policies before doing anything else.
Common citations and what they usually mean in practice:
- Use of permissions — a declared permission with no visible feature, or broad host access with a narrow purpose.
- Remotely hosted code — something in the bundle fetches and executes code, often inside a dependency.
- User data policy — data transmitted that the listing and disclosure form do not describe.
- Deceptive installation tactics — ads or landing pages that misrepresent what the extension does, even if run by an affiliate.
- Single purpose — features added over time that no longer share an obvious purpose.
2. Reproduce the reviewer’s view
Download the exact published version and audit that, not your working tree. The violation is in what shipped.
1# Fetch the published CRX by id and unpack it for inspection.
2EXT_ID=abcdefghijklmnopabcdefghijklmnop
3curl -L -o published.crx \
4 "https://clients2.google.com/service/update2/crx?response=redirect&prodversion=120&acceptformat=crx3&x=id%3D${EXT_ID}%26uc"
5unzip -o published.crx -d published/ 2>/dev/null || true
6grep -rnE "eval\(|new Function|importScripts\(.*https?:" published/ | head
Execution context: your shell. unzip warns about the CRX header but extracts the contents. Grep for the patterns the cited policy is about — for remote code, eval, new Function and remote script loading; for data policy, every fetch and its destination.
3. Decide: fix and resubmit, or appeal
Appeal only if you are confident the finding is wrong and you can show why concretely. An appeal that argues intent (“we would never misuse data”) without addressing the specific evidence is almost always declined and costs days.
Fix and resubmit when the finding is plausible from the reviewer’s side, even if you disagree with the severity. It is usually faster, and a clean resubmission is itself evidence of good faith.
1Appeal template — only for a finding you can refute with specifics
2
3Item: <extension id>, version <x.y.z>
4Cited policy: <section>
5What the reviewer likely saw: <e.g. a fetch to cdn.example.net in vendor/analytics.js>
6Why it does not violate the policy: <e.g. the response is JSON configuration, parsed with
7 JSON.parse and never executed; see src/config.js lines 12–40>
8Evidence: <link to the relevant source, or a short screen recording>
Execution context: this is text for the appeal form. Naming what the reviewer probably saw shows you understood the finding, which is what makes the rest of the argument land.
4. Ship the fix as its own release
The corrective version should contain the fix and nothing else, and its description in the resubmission notes should say exactly what changed.
1Resubmission notes — version 3.2.1
2- Removed the "history" permission; the reading report now uses topSites (src/report.js).
3- Removed vendor/analytics.js; no third-party network requests remain.
4- Privacy disclosure updated to match: no web history collected.
Execution context: the resubmission form. A reviewer comparing the notes against the diff should find no surprises. Mixing a feature release into a corrective one invites a fresh review of everything.
5. Talk to affected users
If the extension was disabled, users saw a store message and nothing from you. A short, factual post on your website and in the listing’s description helps; a notice inside the extension helps once it is re-enabled.
1chrome.runtime.onInstalled.addListener(async ({ reason, previousVersion }) => {
2 if (reason === "update" && previousVersion === "3.2.0") {
3 await chrome.storage.local.set({
4 notice: { id: "reinstated-3.2.1", text: "Reader was briefly disabled while we fixed a permissions issue. Nothing you saved was affected." },
5 });
6 }
7});
Execution context: the service worker, on the corrective update. Keep the tone plain and do not criticise the store in-product — users want to know whether their data is safe and whether they need to do anything.
Preventing the next one
Most takedowns trace back to something that crept in between reviews: a dependency update that added telemetry, an affiliate’s landing page, a permission kept “just in case”. The prevention is a pre-release audit run on every build, not a policy read-through once a year.
1# build/audit.sh — run on the packaged artifact before upload
2set -e
3node build/check-permissions.mjs dist/manifest.json # every permission has a call site
4grep -rqE "eval\(|new Function\(" dist/ && { echo "dynamic code found"; exit 1; } || true
5node build/list-network-hosts.mjs dist/ > hosts.txt # diff against last release
6diff -u releases/last-hosts.txt hosts.txt || echo "network hosts changed — review before upload"
Execution context: your shell, in CI. The host diff is the check that catches a dependency quietly adding a network call — the change that most often turns into a user-data citation. The broader pre-submission audit is in passing Chrome Web Store review.
Cross-browser variation
- Chrome Web Store: issues warnings with deadlines for many violations; can remove listings and remotely disable installed copies. Appeals go through the developer support form referenced in the notice.
- Firefox (AMO): reviewers can disable a version or the whole add-on. Because AMO reviews source, findings are often very specific — a file and line — which makes a targeted fix quicker.
- Safari / App Store: enforcement applies to the containing app. Removal from sale stops new installs; resolution goes through App Store Connect’s resolution centre.
- All three: a takedown on one store is not automatically mirrored on the others, but reviewers do notice. Fix the cause everywhere you ship, not only where it was reported.
Verification
- Confirm the corrective build no longer contains the cited pattern by re-running the audit against the packaged artifact.
- Confirm the manifest’s permissions match the listing’s justifications line for line:
1chrome.runtime.getManifest().permissions;
2// ["storage", "alarms", "topSites"] ← "history" gone, as the notes claim
Execution context: the service worker console of the corrective build. Any permission here without a justification in the dashboard is a finding waiting to happen.
- After reinstatement, install from the store on a clean profile and confirm the extension is enabled and the in-product notice appears once.
- Record the incident and the audit change that would have caught it.
FAQ
How long does reinstatement take?
After a warning, often a normal review cycle once the fix is submitted. After a remote disable, typically longer, because the corrective version gets closer scrutiny. Malware findings are the slowest and are resolved by appeal.
Will users have to reinstall?
After a listing removal, no — installed copies were never touched. After a remote disable, the corrective update usually re-enables it, but some users will have uninstalled in the meantime.
Can I publish a new listing instead?
Doing so to evade enforcement is itself a policy violation and can lead to account termination. Resolve the existing item.
Related
- Passing Chrome Web Store review — the audit that prevents most takedowns.
- Writing a permission justification that passes — keeping the listing and the manifest in step.
- Rolling back a bad extension release — the release mechanics under pressure.
- Store submission and permissions compliance — the parent guide.