mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-08 09:48:20 +01:00
Require the daemon secret and loopback Host/Origin on the design and iOS QA daemons (#4117)
* Require the daemon secret and loopback Host/Origin on the design and iOS QA daemons (GST-1747) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Name the changelog fragment after the branch (GST-1747) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes Review-Finding: p1/red-team#2 reader=red-team Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: refuse cross-site browser requests on the iOS QA loopback, show the expired page for a stale board secret, refuse requests without a Host (GST-1747) Review-Finding: v1/outside-voice#1 reader=outside-voice Review-Finding: v1/adversarial-native#2 reader=adversarial-native Review-Finding: v1/adversarial-native#5 reader=adversarial-native Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: show the secret segment in the documented design board URL (GST-1747) Review-Finding: v1/adversarial-native#1 reader=adversarial-native Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: keep the daemon token fixtures on one line so the credential scan reads them as code (GST-1747) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: cover the Sec-Fetch-Site refusal, the expired board page and the no-Host 403 in the changelog fragment (GST-1747) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
de5cb247e0
commit
6cf00aee9c
21 files changed
+413
-89
No files matched your search
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Request checks for daemons bound to a loopback port. Binding 127.0.0.1
|
||||
* keeps other machines out but not other origins on this machine: a browser
|
||||
* page can send requests to the port, and a page served under a hostname
|
||||
* that resolves to 127.0.0.1 arrives with that hostname as Host. Serving
|
||||
* only loopback Host values and same-origin (or absent) Origin values keeps
|
||||
* the port to local clients that address it directly.
|
||||
*/
|
||||
|
||||
const LOOPBACK_HOSTNAMES = ['127.0.0.1', 'localhost', '[::1]'];
|
||||
|
||||
function isLoopbackAuthority(authority: string, port: number): boolean {
|
||||
const normalized = authority.toLowerCase();
|
||||
return LOOPBACK_HOSTNAMES.some((hostname) => normalized === `${hostname}:${port}`);
|
||||
}
|
||||
|
||||
/** Why a request to a loopback daemon on `port` must be refused, or null to serve it. */
|
||||
export function loopbackRequestRefusal(
|
||||
host: string | null | undefined,
|
||||
origin: string | null | undefined,
|
||||
port: number,
|
||||
): 'host_not_loopback' | 'cross_origin' | null {
|
||||
if (!host || !isLoopbackAuthority(host, port)) return 'host_not_loopback';
|
||||
if (origin === null || origin === undefined) return null;
|
||||
if (!origin.startsWith('http://') || !isLoopbackAuthority(origin.slice('http://'.length), port)) return 'cross_origin';
|
||||
return null;
|
||||
}
|
||||
Reference in new issue
Block a user