Series · 3 partsBrowser-to-Native Trust BoundariesPart 3 · You are here
  1. 1The Extension Was Sandboxed. The Native Host Was Not.
  2. 2The Page Never Had Permission. The Extension Did.
  3. 3The Package Was Signed. The Update Was Still a Security Decision.You are here

The boundary in 60 seconds

A valid extension signature answers a narrow question: did this package come from the identity the browser expects for this extension? It does not prove that the release was produced from the reviewed commit, that the build runner was clean, that the publisher account intended this upload, that permissions did not expand, or that remote configuration cannot activate a new capability.

Chrome automatically checks for extension updates on startup and every few hours. An available Manifest V3 update is installed after the extension becomes idle. Managed environments may pin a version or override its update source. Firefox-listed add-ons update through AMO; self-distributed add-ons may use an HTTPS update manifest and still require Mozilla signing for release and beta Firefox.

Those controls establish distribution mechanics. The security decision remains:

Which reviewed source, build identity, artifact digest, publisher action, permission set, rollout cohort, and runtime configuration produced the code now exercising extension authority?

This final part of the series builds a method for answering that question without publishing a malicious extension or touching a real user fleet.

One release, seven principals

EXTENSION RELEASE AUTHORITY GRAPHSIGNER CONTINUITY IS NOT RELEASE AUTHORIZATION SOURCEcommit · reviewINTENT BUILDrunner · depsTRANSFORM ARTIFACTdigest · SBOMEVIDENCE PUBLISHERaccount · tokenUPLOAD UPDATEstore · URLDELIVERY BROWSERinstalled fleetEFFECT Identity factscommit signer · workflow IDpublisher actor · store itemWHO MOVED THE RELEASE? Artifact factsdigest · manifest · permissionsdependency lock · build recipeWHAT WAS DELIVERED? Runtime factscohort · effective configpermission · privileged effectWHAT BECAME POSSIBLE? RELEASE AUTHORIZATION = IDENTITY + ARTIFACT + RUNTIME DELTA
Figure 1. Every handoff can preserve a valid extension identity while changing the evidence needed to authorize the release.
PrincipalSecurity decisionEvidence that must survive
Source reviewerIs this change intended and bounded?Commit, review, changed files, threat note
Build serviceDid the approved source produce this package?Workflow identity, clean runner, dependency lock, logs
Artifact storeIs this the exact reviewed output?SHA-256 digest, manifest snapshot, SBOM, provenance statement
Publisher accountWas this upload authorized?Strong authentication, actor, timestamp, artifact digest
Store or update hostWhich version is offered to which client?Version mapping, update URL, rollout record
BrowserWhich package is actually installed?Extension ID, version, permissions, update source
Runtime control planeWhich behavior is active now?Effective config, cohort, expiry, audit event

What the platform proves—and what it does not

Platform controlEstablishesDoes not establish
Package signatureContinuity with the expected extension identityThe release is benign or matches reviewed source
Store reviewSubmitted package passed the store’s current processPublisher credentials, backend config, or future releases remain safe
Manifest V3 packaged codeExtension logic is bundled rather than fetched as ordinary remote codeRemote data cannot act as a hidden instruction language
Permission warningA declared permission delta may be visible or block activationExisting broad permissions are used only for the old purpose
HTTPS update manifestNetwork delivery has server authentication and integrity in transitThe update origin and publisher pipeline are correctly authorized
Version pinA cohort remains on one versionThe pinned version is safe or receives a critical fix
Staged rolloutExposure can be limited over timeThe selected cohort is observed or rollback is complete

The distinction matters because an extension update is not merely new code. It is a fleet-wide change to a principal that may already hold tabs, cookies, storage, downloads, host access, or a native messaging bridge.

The five failure families

Failure familyBoundary lostTypical observable result
Publisher takeoverStore account or upload token becomes sufficient release authorityValidly distributed unauthorized package
Build substitutionCI output is not bound to reviewed sourceSigned artifact contains unreviewed code or dependencies
Permission driftReview considers code but not effective capability deltaUpdate gains broader host or browser access
Configuration-as-codeRemote JSON selects operations rather than bounded dataStore-reviewed package activates unreviewed behavior
Rollout blindnessRelease success is inferred from upload completionVulnerable or unauthorized versions remain active in cohorts

Remote hosted code restrictions are an important control, but the research question is broader. A remote response does not need to contain JavaScript to become logic. A configuration grammar with arbitrary operation names, URLs, selectors, scripts, or rule expressions can transfer the security decision out of the reviewed package.

A bounded synthetic release lab

The lab needs no store upload and no real user. Use a disposable extension ID, a local mock update service, two inert packages, and one canary capability: incrementing a counter in extension-local storage. Version 1.0.0 may increment only release_a; version 1.0.1 is tested against permission, artifact, configuration, and rollout gates before it may increment release_b.

Parallel extension release pipelines comparing provenance-linked delivery with a validly signed but authorization-drifting release.
Evidence plate 01. The lower path preserves distribution identity while runtime authority diverges through one unmeasured control point.

The positive test proves only that the authorized package and cohort can change the intended canary. Negative controls must show that a different digest, unexpected permission, expired config, wrong rollout cohort, and replayed approval create no state change.

Build an artifact contract

Record release facts next to the package rather than reconstructing them after an incident.

{
  "extension_id": "lab-extension",
  "version": "1.0.1",
  "source_commit": "8d6d...e21",
  "workflow_identity": "release.yml@refs/tags/v1.0.1",
  "artifact_sha256": "7f4a...91c",
  "manifest_sha256": "c1e3...a42",
  "permissions": ["storage", "activeTab"],
  "host_permissions": ["https://lab.invalid/*"],
  "sbom_sha256": "0bd2...723",
  "built_at": "2026-08-31T07:00:00Z"
}

The contract is useful only if the publisher verifies it against the artifact it uploads. A digest created after an uncontrolled upload is documentation, not authorization.

Treat manifest changes as security changes

The manifest is the extension’s declared authority surface. Diff it separately from application code and fail closed on unexpected additions.

const authority = (manifest) => ({
  permissions: [...(manifest.permissions ?? [])].sort(),
  optional_permissions: [...(manifest.optional_permissions ?? [])].sort(),
  host_permissions: [...(manifest.host_permissions ?? [])].sort(),
  content_scripts: (manifest.content_scripts ?? []).map(
    ({ matches, all_frames, world }) => ({
      matches: [...matches].sort(),
      all_frames: Boolean(all_frames),
      world: world ?? "ISOLATED",
    }),
  ),
  externally_connectable: manifest.externally_connectable ?? null,
  update_url: manifest.update_url ?? null,
});

Compare the normalized result with the previous production release. New host patterns, all_frames, external callers, native messaging, debugger access, or an update-source change require a named reviewer and an explicit rationale. A version bump is not that rationale.

Keep remote configuration below the policy line

Safer remote configuration selects among packaged, bounded behaviors:

{
  "schema": 2,
  "issued_at": "2026-08-31T07:00:00Z",
  "expires_at": "2026-08-31T08:00:00Z",
  "cohort": "canary-05",
  "flags": { "new_panel": false },
  "limits": { "batch_size": 20 }
}

High-risk configuration accepts a dispatcher, URL, expression, selector, or script-like data:

{
  "operation": "run",
  "target": "https://runtime-selected.example/*",
  "steps": [{ "action": "inject", "payload": "server-controlled" }]
}

Reject unknown keys, enforce a small schema, bind the document to a release version and cohort, verify expiry, and default to the last known safe packaged behavior. Configuration signatures can authenticate a control plane; they do not make an overpowered grammar safe.

Rollout is a state machine, not a percentage

FAIL-CLOSED RELEASE STATE MACHINEPROMOTION REQUIRES NEW EVIDENCE; TIME DOES NOT PROMOTE A RELEASE CANDIDATEdigest bound CANARY5% observed STAGED25% · 50% PRODUCTIONversion proven QUARANTINEhalt updateROLLBACKknown-safe build DENIAL · CRASH · PERMISSION DRIFT · UNKNOWN DIGEST → STOP
Figure 2. Promotion is an authorization event backed by cohort evidence; rollback must also identify the artifact and effective configuration.

Reproduction methodology

  1. Inventory release identities, update sources, store roles, CI credentials, and runtime config.
  2. Build the same tagged source twice in isolated runners and compare outputs or explain every nondeterministic byte.
  3. Capture the unpacked manifest and package digest before upload.
  4. Test an unexpected permission and host pattern; the release gate must reject both.
  5. Offer an authorized package only to a synthetic canary cohort.
  6. Replay the approval with a different digest; it must not publish or promote.
  7. Serve expired, oversized, unknown-key, wrong-cohort, and wrong-version configuration.
  8. Prove rollback removes the tested effect and identify clients that remain on the old version.

Test matrix

DimensionVariantsSecure result
SourceReviewed tag, moved tag, unreviewed commitOnly immutable reviewed source builds
BuildClean runner, altered dependency, reused workspaceArtifact or provenance delta blocks release
ArtifactExpected digest, repackaged ZIP, manifest driftOnly exact authorized digest proceeds
PublisherHuman MFA, scoped workload identity, stale tokenShort-lived scoped identity; stale token denied
PermissionsSame, added optional, broad host, native bridgeAny authority expansion requires explicit review
Update sourceStore, approved enterprise URL, unexpected overrideInventory matches policy and installed state
ConfigurationValid, expired, replayed, unknown key, wrong cohortInvalid documents create no privileged effect
RolloutCanary, staged, pinned, offline, rollbackEvery installed cohort is observable and bounded

Evidence matrix

ClaimPositive evidenceNegative controlStrong conclusion
Reviewed source produced the packageCommit, workflow identity, reproducible output, matching digestMoved tag or changed dependency produces a different or rejected artifactTested artifact is bound to reviewed source and build context
Upload was authorizedPublisher actor and exact digest recordedSame approval with another digest is deniedApproval cannot authorize an arbitrary package
Authority did not driftNormalized manifest equals approved capability setAdded host or permission blocks promotionTested release cannot silently expand declared authority
Remote config is dataValid bounded schema changes only documented flagsOperation, URL, unknown key, expiry, and replay are rejectedTested control plane cannot select arbitrary privileged actions
Canary limits exposureOnly synthetic cohort receives candidate and reports version/digestNon-canary client remains on productionTested rollout selector is enforced
Rollback is completeKnown-safe version and config replace candidateCandidate effect and digest disappear from every observed cohortTested fleet returned to the recorded safe state

Hardening order

  1. Require phishing-resistant MFA for store owners and remove unused publisher roles.
  2. Replace long-lived upload secrets with short-lived, repository-bound workload identity where the store supports it.
  3. Build from immutable tags in isolated runners; pin actions and dependencies.
  4. Generate package digest, manifest snapshot, SBOM, and provenance before upload.
  5. Make the publisher accept only an approved digest and version.
  6. Gate manifest authority changes separately from code review.
  7. Keep remote config typed, bounded, expiring, cohort-bound, and incapable of selecting code-like operations.
  8. Measure installed versions and effective configuration by cohort.
  9. Rehearse both store rollback and kill-switch behavior without depending on the compromised publisher path.

Detection and incident evidence

Preserve store audit events, role changes, failed MFA, CI workflow identity, dependency-lock changes, artifact digests, manifest authority diffs, update-source policy, installed versions, configuration hashes, and privileged operation summaries. Never log cookies, page contents, tokens, or full URLs when a stable origin or operation identifier is sufficient.

{
  "event": "extension_release_observed",
  "extension_id": "lab-extension",
  "version": "1.0.1",
  "artifact_sha256": "7f4a...91c",
  "manifest_policy": "approved",
  "cohort": "canary-05",
  "config_sha256": "2f91...bb0",
  "decision": "promote-denied",
  "reason": "unexpected-host-permission"
}

Final model

The package signature is necessary evidence, not the final verdict.

TRUSTED RELEASE
= expected publisher identity
+ reviewed immutable source
+ controlled build identity
+ authorized artifact digest
+ reviewed authority delta
+ bounded runtime configuration
+ observable rollout and rollback

Part 1 followed a message into a native process. Part 2 followed a page into extension authority. Part 3 closes the loop by proving how the privileged extension code reached the browser in the first place. The complete series has one rule: reachability, identity, signing, and delivery are inputs to authorization; none is authorization by itself.

Sources & freshness

How current is this note?

Sources checkedAugust 31, 2026

The latest source-review, content-update, or publication date is shown.

ReviewPublic sources reviewed

Primary public records were checked. Environment-specific behavior remains outside the claim unless separately reproduced.