IHOR.DEVKNOWLEDGE_BASE
MENU

~/blog / Security / web-accessible-resources-without-data-leaks.md

// guide · 4 min read

Web Accessible Resources Without Data Leaks

Expose only required extension assets to named origins, avoid broad wildcards, understand dynamic resource URLs, and review web-accessible HTML and message surfaces.

Quick answer

Web-accessible resources expose packaged files to selected web origins or other extension IDs. Declare only the assets a page actually needs, such as an injected icon or stylesheet asset. A content script itself does not need to be declared web-accessible just to run. Never use resources: ["*"] as a default when a short asset list satisfies the feature.

Exposure is not authorization and not secret storage. A page allowed to access a file can inspect its contents, and a web-accessible HTML surface can become another input boundary. Review configuration, debug artifacts, and data files before including them in any wildcard. Keep confidential information out of the package regardless of this setting.

Practical implementation steps

Inventory page-loaded assets

Trace URLs assigned to injected images, styles, fonts, and iframes. Extension-owned pages loading their own assets are a different case from web pages loading extension assets. Font Picker's documented on-page inspector is a useful UI scenario, but its description does not establish a specific resource declaration. Verify the release manifest before attributing exposure to a product.

Scope files and callers

Prefer exact file paths and known origins. A resource wildcard can recursively expose files added by a future build. For matches in this field Chrome uses the origin and requires the path /*; this is not a way to restrict access to one page path. Use extension_ids when the intended consumer is another known extension rather than a website.

Evaluate dynamic URLs accurately

use_dynamic_url requests a per-session dynamic ID, regenerated after browser restart or extension reload. Generate asset URLs through runtime.getURL and avoid caching an old URL across sessions. Dynamic URLs can reduce stable probing opportunities, but do not make an intentionally exposed asset confidential. Test the relevant browser version and reload lifecycle.

Review active surfaces separately

An exposed HTML page needs careful input handling for query parameters, fragments, and messages. Do not treat a navigation to an extension URL as proof of a trusted requester. Keep privileged commands separate, validate senders, and avoid inserting page-controlled values as HTML. If a passive image is enough, exposing a full interactive page creates unnecessary review work.

Implementation example

This manifest fragment exposes one decorative asset to one illustrative HTTPS origin. Add it to a valid extension manifest and generate the URL from the content script. It grants resource access, not host access for other operations.

{
  "web_accessible_resources": [{
    "resources": ["assets/inspector-icon.svg"],
    "matches": ["https://app.example.com/*"],
    "use_dynamic_url": true
  }]
}
const icon = document.createElement("img");
icon.src = chrome.runtime.getURL("assets/inspector-icon.svg");
icon.alt = "";
document.documentElement.append(icon);

Use meaningful alt text if the icon communicates information; the empty value here assumes nearby text supplies its meaning. In the release review, request the asset from an intended and an unintended origin and verify the expected outcome after reload. Inspect the ZIP to confirm no wildcard brings in extra files.

Tradeoffs and alternatives

Exact assets make changes explicit but require updating the declaration when a feature adds files. Directory patterns reduce maintenance at the cost of future exposure. Separate rules for distinct callers are easier to review than one broad rule. Choose convenience only after inspecting everything that the pattern makes reachable.

Common mistakes

  • Exposing the entire build directory.
  • Declaring content scripts unnecessarily.
  • Using a page path in matches as an access restriction.
  • Treating dynamic URLs as encryption or authentication.
  • Publishing debug data through recursive wildcards.

Production checklist

  • Each exposed file has an actual page consumer.
  • Caller origins or extension IDs are scoped.
  • Wildcards are checked against the final ZIP.
  • Dynamic URL reload behavior is verified if used.
  • Active HTML surfaces validate all inputs.
  • No secrets or confidential records are packaged.

FAQ

Does runtime.getURL make a resource public?

No. It constructs the extension URL. The manifest's web-accessible rules determine whether a web origin can access that resource.

Can matches limit one application path?

Not in this field. Chrome matches origins and requires /*. Enforce any feature path policy in the relevant code instead.

Conclusion

Expose passive assets narrowly and treat any exposed active surface as a new input boundary. Review the packaged file set every release, because an unchanged wildcard can publish newly added files.

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?

Browser tools with a clear purpose, focused permissions, and a maintainable Manifest V3 architecture.