Skip to content

Write down why the remote-code answer is no - #72

Merged
sotashimozono merged 2 commits into
mainfrom
remote-code-reasoning
Sep 15, 2026
Merged

sotashimozono merged 2 commits into
mainfrom
remote-code-reasoning

Conversation

@sotashimozono

Copy link
Copy Markdown
Member

souta is filling the Chrome Web Store form and asked whether we use remote code. The answer is no, but it is not an obvious no and the reason was written nowhere.

applyPac fetches http://127.0.0.1:<port>/proxy.pac from the user's own daemon and hands the text to chrome.proxy as pacScript.data. Chrome's definition is "anything that is executed by the browser that is loaded from someplace other than the extension's own files", and a PAC is JavaScript. So the case that could contradict the answer exists, and proxy is a permission that draws human review of a 7 KB background.js where those three lines are visible.

It is still no, for reasons now recorded beside the answer: the PAC runs in the browser's network stack rather than in the extension; chrome.proxy is a first-party API whose documented input is exactly a PAC string; and it arrives from loopback rather than from a server the author controls, which is the thing the policy exists to prevent.

The fallback is scoped in the same place, because the moment to work it out is not the moment a rejection arrives: the PAC is a function of the suffix and the port and the extension knows both, so generating it locally settles the question. What the fetch was for survives — the suffix stays data the daemon reports, so changing it still needs no extension release — and an e2e check running both generators against the same hosts covers the one thing lost.

Decision to submit with "no" for now is souta's; this only makes it a decision with its reasoning attached rather than an assertion.

souta registered the developer account and asked whether CI could take it from
there. Mostly yes, and the line is not where you would guess.

The Chrome Web Store API cannot create a listing. Description, screenshots,
category and the data disclosure are not reachable from it, and the extension ID
does not exist until the Store listing and Privacy tabs have been filled in by a
person. So the first submission is by hand and always will be. Every update
after it is a package upload and a publish, and both are API calls.

`store.yml` does those on a published release. The human gate is not removed, it
moves: merging the release PR is the decision, and what reaches the store is the
package that was built, tested and attached to that release rather than one
dragged into a browser.

A service account rather than a refresh token. A refresh token issued while the
OAuth consent screen is still in "Testing" expires after a week, so the pipeline
would work today and fail next month having changed nothing. v2 of the API takes
service accounts, which do not expire; the JSON key is one secret and the
dashboard takes the account's email under Account.

It refuses before authenticating when a secret is missing, and names which. An
authentication error twenty lines into a log is the same fact told worse.

Two things the docs say and experience will otherwise teach: the API does not set
visibility, so an item whose visibility was changed by hand must be published by
hand once before the API will do it again; and a version cannot be uploaded
twice, which is what the `versions agree` check has been protecting all along.

The endpoints and the service-account flow are from the Chrome for Developers
documentation rather than memory, and the action SHA resolves to the v3.0.0 tag
rather than the moving `v3`.

Signed-off-by: Souta <shimozono-sota631@g.ecc.u-tokyo.ac.jp>
The form asks whether the extension uses remote code and the answer is no, but
it is not an obvious no and the reason was nowhere.

`applyPac` fetches `http://127.0.0.1:<port>/proxy.pac` from the user's own
daemon and hands the text to `chrome.proxy` as `pacScript.data`. Chrome defines
remotely hosted code as "anything that is executed by the browser that is loaded
from someplace other than the extension's own files", and a PAC is JavaScript.
So the case that could contradict the answer exists, and a reviewer reading
seven kilobytes of `background.js` will see it.

It is still no: the PAC runs in the browser's network stack rather than in the
extension, `chrome.proxy` is a first-party API whose documented input is exactly
this, and it arrives from loopback rather than from a server the author
controls -- which is the thing the policy exists to prevent.

The fallback is scoped here too, because the moment to work it out is not the
moment a rejection arrives. The PAC is a function of the suffix and the port and
the extension knows both, so generating it locally settles the question without
losing what the fetch was for: the suffix stays data the daemon reports, so
changing it still needs no extension release.

Signed-off-by: Souta <shimozono-sota631@g.ecc.u-tokyo.ac.jp>
@codecov

codecov Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@sotashimozono
sotashimozono merged commit 8e58508 into main Sep 15, 2026
18 checks passed
@sotashimozono
sotashimozono deleted the remote-code-reasoning branch September 15, 2026 03:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant