IHOR.DEVKNOWLEDGE_BASE
MENU

~/blog / Security / remote-code-rules-in-manifest-v3.md

// guide · 4 min read

Remote Code Rules in Manifest V3

Find Manifest V3 remote executable code in packaged files and dependencies, separate data from logic, and remove CDN imports or downloaded code before submission.

Quick answer

For ordinary Manifest V3 functionality, bundle executable JavaScript and WebAssembly with the extension. Do not load a CDN script, import a remote module at runtime, or fetch text and evaluate it as code. Remote JSON or other data is a different category, but calling executable instructions “configuration” does not make them permissible. Review the exact packaged output, including third-party dependencies.

This article is about store-reviewable executable behavior. CSP describes runtime resource restrictions and is related, but a package passing your local CSP checks does not prove store compliance. Specialized APIs and isolated contexts have specific rules; they are not generic escape hatches for updating extension logic without a reviewed release.

Practical implementation steps

Search the actual build

Inspect generated JavaScript, HTML, worker imports, WASM loaders, and dependency chunks. Search for remote URLs, importScripts, dynamic imports, script element creation, eval, and Function construction. A URL match is a lead, not proof: it might be a documentation link or data endpoint. Follow the value to its use and classify whether the browser executes the fetched content.

Review transitive dependencies

An SDK can fetch optional code even when your source imports only one feature. Remove unused entry points, choose an extension-compatible build, or replace the package. Tree shaking helps only if the offending path is actually absent from the submitted bundle. Keep a reproducible dependency configuration; editing a minified output by hand is easy to lose during the next build.

Keep remote data within a bounded schema

A service can return user content or configuration values for logic already bundled in the extension. Define allowed keys, types, ranges, and version handling. Do not accept arbitrary code strings, module URLs, or instructions that assemble new executable behavior. Validation also prevents an unexpected configuration value from disabling important access checks or expanding data collection.

Fix the cause before resubmission

If review identifies remote code, map the named file or behavior to the dependency and replace the execution path. Rebuild from clean inputs and inspect the new package. Explain the concrete change in the resubmission rather than promising the old path is “not used.” Do not invent a successful store outcome based on a local search.

Implementation example

This validator accepts a small display configuration without accepting executable logic. It deliberately rejects unknown versions and out-of-range values. It does not authorize any particular remote-data use under privacy policy; review that separately.

type DisplayConfig = { version: 1; compact: boolean; maxItems: number };
function parseDisplayConfig(value: unknown): DisplayConfig {
  if (!value || typeof value !== "object") throw new Error("Invalid config");
  const x = value as Record<string, unknown>;
  const allowed = new Set(["version", "compact", "maxItems"]);
  if (Object.keys(x).some(key => !allowed.has(key))) throw new Error("Unknown key");
  if (x.version !== 1 || typeof x.compact !== "boolean" ||
      typeof x.maxItems !== "number" || !Number.isInteger(x.maxItems) ||
      x.maxItems < 1 || x.maxItems > 50) throw new Error("Invalid config");
  return { version: 1, compact: x.compact, maxItems: x.maxItems };
}

Use a known safe default when fetching or parsing fails, and do not evaluate the response. Keep configuration out of permission and authorization decisions unless that specific boundary is deliberately designed and validated. A JSON parser alone cannot decide whether a data-driven interpreter violates the executable-code model.

Tradeoffs and alternatives

Bundling dependencies increases package size and ties executable updates to the release process, but makes behavior inspectable. A remote service can perform server-side work and return bounded results, with added availability and privacy considerations. Prefer a smaller compatible dependency when a large package introduces unused remote loaders. Do not trade away the review boundary merely to reduce ZIP size.

Common mistakes

  • Auditing source files while submitting different compiled output.
  • Assuming a well-known SDK is exempt.
  • Leaving a remote loader in unused packaged code.
  • Calling fetched code a JSON setting.
  • Treating a sandbox or debugger as a general policy workaround.

Production checklist

  • All executable assets are accounted for in the package.
  • Remote URL matches have been traced to their use.
  • Dependency loaders and optional entry points are inspected.
  • Remote configuration has a bounded runtime schema.
  • The submitted ZIP is reproducible from reviewed inputs.
  • Any specialized API use is checked against its exact policy.

FAQ

Is remote JSON always acceptable?

No blanket claim is safe. Ordinary data differs from executable code, but its purpose, interpretation, and user-data handling still matter. Inspect the consumer and applicable store policies.

Can tree shaking solve a remote-code violation?

It can when it removes the offending code from the final package. Verify the built artifact instead of relying on a configuration option or an assumption that an import is unreachable.

Conclusion

Audit the code users receive, trace every remote executable path, and replace it with packaged logic or a properly bounded service result. Keep policy evidence tied to the release artifact so a dependency upgrade cannot silently restore a removed loader.

Primary sources

Ihor Kharchyshyn

Independent full-stack product engineer writing source-backed implementation guides for browser extensions and modern web products.

Need this implemented in a real product?

Explore relevant product case studies or share the context for a web application, Chrome extension, API, or SaaS build.