# Web accessible resources are scoped

- **Pattern:** `ab-001338` (`extension-permissions-security.host-permissions-minimization.web-accessible-scoped`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001338
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001338)

## Why it matters

CWE-200 (Information Exposure) applies directly: resources listed in `web_accessible_resources` with `matches: ['<all_urls>']` are fetchable by any website on the internet. This enables extension fingerprinting — a site can probe for specific resource paths to detect which extensions a user has installed, bypassing privacy expectations. OWASP A01 (Broken Access Control) governs the broader failure: the resource exposure is an access grant, and that grant should be minimal. Chrome's `web_accessible_resources` MV3 API was specifically redesigned to require a `matches` array precisely to close the fingerprinting vector that the MV2 API left open.

## Severity rationale

Low because globally accessible web resources enable reliable extension fingerprinting by any website, leaking extension presence to third-party tracking and analytics without user awareness.

## Remediation

Scope every `web_accessible_resources` entry in `manifest.json` to the specific domains that actually need access to those resources.

```json
"web_accessible_resources": [{
  "resources": ["icon.png", "injected.css"],
  "matches": ["https://yourdomain.com/*"]
}]
```

If a resource is only needed by your own content scripts (not by external pages), omit it from `web_accessible_resources` entirely — content scripts can always load resources from `chrome.runtime.getURL()` without needing external accessibility.

## Detection

- **ID:** `web-accessible-scoped`
- **Severity:** `low`
- **What to look for:** List all entries in `web_accessible_resources` from `manifest.json`. For each resource, check the `matches` array to verify it is scoped to specific domains rather than `<all_urls>`. Count the number of globally exposed resources.
- **Pass criteria:** All web accessible resources are exposed only to specific `matches` or `extension_ids`. No more than 0 resources use `matches: ["<all_urls>"]` when they do not need global exposure. Report the count of scoped vs globally accessible resources.
- **Fail criteria:** `matches: ["<all_urls>"]` is used for resources that don't need to be globally available.
- **Skip (N/A) when:** `web_accessible_resources` not used.
- **Detail on fail:** `"Resources are web-accessible to all URLs. This allows any site to fingerprint your extension or potentially exploit it."`
- **Remediation:** Scope accessibility in `manifest.json`. If a resource is only for a specific site, list only that site.

  ```json
  "web_accessible_resources": [{ "resources": ["icon.png"], "matches": ["https://yourdomain.com/*"] }]
  ```

## External references

- cwe CWE-200
- owasp A01
- external chrome-web-accessible-resources — https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources

Taxons: access-control

HTML version: https://auditbuffet.com/patterns/ab-001338
