fix(control ui): accept paired device token for assistant media auth#70741
Conversation
🔒 Aisle Security AnalysisWe found 3 potential security issue(s) in this PR:
1. 🟡 Authentication tokens accepted via query string on Control UI assistant-media endpoint
DescriptionThe Control UI assistant-media endpoint explicitly enables query-string authentication ( Why this is risky:
Vulnerable code paths include:
RecommendationPrefer Authorization headers (or cookies with proper CSRF defenses) and disable query-string tokens for authenticated requests. Fix option A (recommended): remove query token support // Do not allow query tokens
await authorizeControlUiReadRequest(req, res, {
...,
allowQueryToken: false,
});
function resolveControlUiReadAuthToken(req: IncomingMessage): string | undefined {
return getBearerToken(req) ?? undefined;
}Fix option B (if query token is unavoidable for some clients):
2. 🟡 Rate-limit bypass: successful device-token auth resets shared-secret auth throttling for same IP
DescriptionIn
This allows an attacker who possesses any valid device token (operator role) to repeatedly clear the shared-secret failure counter for the same
Because the limiter key is RecommendationDo not reset the shared-secret scope on successful device-token authentication. Instead, only reset the scope corresponding to the credential type that was successfully validated: if (deviceTokenOk) {
opts.rateLimiter?.reset(clientIp, AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN);
// Do not reset shared-secret scope here.
resolvedAuthResult = { ok: true, method: "device-token" };
}If you want a “global reset” behavior after any successful auth, ensure the shared secret cannot be brute-forced from the same endpoint (e.g., separate endpoints/scopes, require explicit shared-secret auth to reset shared-secret counters, or add an additional per-account/per-credential identifier so a device-token holder cannot clear another credential’s failures). 3. 🟡 Potential DoS from linear scan of paired devices on each Control UI request
Description
Vulnerable code: const pairing = await listDevicePairing();
for (const device of pairing.paired) {
const operatorToken = device.tokens?.[CONTROL_UI_OPERATOR_ROLE];
...
if (!verifyPairingToken(token, operatorToken.token)) continue;
const verified = await verifyDeviceToken({ deviceId: device.deviceId, token, ... });
if (verified.ok) return true;
}RecommendationAvoid per-request linear scans and repeated state loads. Mitigations (pick one or combine):
Example (conceptual): // Persist an index of tokenHash -> { deviceId, role }
const tokenHash = sha256base64url(token);
const hit = pairing.tokenIndex[tokenHash];
if (!hit) return false;
return (await verifyDeviceToken({ deviceId: hit.deviceId, token, role: hit.role, scopes: [...] })).ok;Analyzed PR: #70741 at commit Last updated on: 2026-04-23T23:19:16Z |
Greptile SummaryThis PR moves assistant-media auth from a shared-secret query token to an The gateway-side change ( Confidence Score: 5/5Safe to merge; all findings are non-blocking style and quality observations. Both inline findings are P2. The blob URL accumulation only manifests on token rotation (uncommon in practice) and the eager-download tradeoff is an intentional design decision. No correctness, security, or data-integrity defects were found. ui/src/ui/chat/grouped-render.ts — blob URL lifecycle when the auth token rotates
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6e1e7cf6c8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
ad61d83 to
f2ad888
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f2ad888fa7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ca60f713fd
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Fixes #70505 (partially)
assistant-media, including the existing?token=Control UI pathFollow-up:
Tests:
pnpm test src/gateway/control-ui.http.test.tspnpm test ui/src/ui/chat/grouped-render.test.ts