Repository navigation
hub: fixes and improvements for hub security and redaction #354
Copy link
Copy link
Closed
Labels
bugSomething is broken or shows wrong dataSomething is broken or shows wrong datafeatureA feature request or a pull request that adds oneA feature request or a pull request that adds one
Description
Context
Fixes and improvements from a code audit of hub security and redaction, done in October 2026. Roadmap work lives in #340, #341, #342 and #343. Items marked (to confirm) were not reproduced; check them before fixing.
Problems
Medium
- No remote access in the Vite plugin:
isAllowedHubRequestrefuses every peer that is not a loopback socket, even whenallowedHosts,allowedOriginsandauthare set. Docker port publishing (peer172.17.0.1), devcontainer or VM forwarding and a phone on the LAN always get 403. When auth is on, allow non-loopback peers whoseOriginandHostpass the policy, or add an explicitallowRemoteoption, and say why in the 403 message (packages/devtools/src/vite.ts:151,27-31). -
serializeskipskey=valuemasking:serializeandredactTextuse theforms-privacyredactMessage, which has noTEXT_PAIR/URL_PAIRmasking and no sessionknownSecrets, unlikerouter.tsredactText. A string such as'password=hunter2&user=a'or'api_key=XYZ'in component state, signals or NgRx state goes out unmasked. Move the pair logic andknownSecretsinto one shared module used byserialize, router and HTTP, and add a leak test for{ note: 'token=abc123' }(packages/devtools/src/serialize.ts:1,20-22,89;packages/devtools/src/router.ts:223-296). - Prefixed secrets not detected by value: value-shape detection covers only JWT, Bearer, Basic, Digest and Token. Stripe
sk_live_/rk_live_, GitHubghp_/gho_/github_pat_, Slackxoxb-/xoxp-, AWSAKIA…, GoogleAIza…, PEM private-key blocks and Sentry DSNs (https://key@host, whichUSERINFOmisses because it needsuser:pass) pass through under neutral keys. Add a small table of high-confidence prefixes and a-----BEGIN … PRIVATE KEY-----pattern toredactCredentials(packages/devtools/src/forms-privacy.ts:179-187;packages/devtools/src/credential-redact.ts:9).
Low
- Secret-name gaps and over-matches:
SECRET_WORDSmissessignature,sig,salt,nonce,privkey,dsn,refresh,sid,mfa,recoveryandauthon its own.cardandccare whole words, socardTitle,cardIdandccList(email CC) are masked. Movecardandccto pairs only (cardnumber,ccnum,cardcvc,ccexp), add the missing words, and add table-driven tests for false negatives and false positives (packages/devtools/src/forms-privacy.ts:24-65,131-134). - One bad node hides the whole value:
Object.keys(v)and theinstanceofchecks run outside any per-nodetry, so a revoked Proxy throws to the outercatchand the whole root becomes'[Unreadable]'. Property reads also go through getters on live page objects, which can run side effects. Wrap each node intry/catch, and read throughObject.getOwnPropertyDescriptor, showing accessors as'[Getter]'(packages/devtools/src/serialize.ts:97-160). - Errors lose
cause: anErroris reduced toname: message, socause(often the failing request) is lost. Serializecauseone level deep throughwalk, redacted (packages/devtools/src/serialize.ts:100). - Custom origin registry drops the extension: an array
allowedOriginsgetsPANGULAR_EXTENSION_ORIGINSappended, but a customWsOriginRegistryis used as is, so the published extension is refused, andallowedOrigins: falseturns every check off with no log line. Wrap custom registries so they also accept the extension origins, and warn once when the check is off (packages/devtools/src/hub.ts:65-71). - Any loopback port is trusted:
isAllowedHubOriginaccepts any http(s) origin whose hostname is loopback, so another local app on a different port can open the hub WebSocket and RPC. By default accept only the dev server's own origins plus the extension and configured origins, and treat other loopback ports as remote, which needs the token (packages/devtools/src/vite.ts:55).
Improvements
- One redaction module (
redactText,redactUrl,redactValue,isSecretKey) replacing the tworedactMessagefunctions, plus a leak test that pushes a corpus of secrets (Stripe, GitHub, AWS, PEM, DSN, URL-encoded) through every collector's output path (forms-privacy.ts,router.ts,serialize.ts,http-redact.ts,credential-redact.ts,json-text-redact.ts,analog-redact.ts). - An opt-in mask for high-entropy strings of 32 or more characters under neutral keys, as Sentry and Datadog scrubbers do (
credential-redact.ts,config.ts). - Redaction counts in the panel and in agent responses (for example "3 values masked: key, bearer, jwt"), so users can tell masking happened and find the unmask options (
serialize.ts,app/src). - Log refused requests by peer and
Hostas well asOrigin, and add a loopback-only security status endpoint the panel can show (vite.tsblockedOriginReporter,hub.ts). - A
pangular token --rotateCLI command to rotate the MCP token on demand (hub.ts, CLI).
Already tracked elsewhere
- No
Hostcheck in the Vite gate, so DNS rebinding passes: phase 1 of 4: safe by default and wired into your workflow #340. - No loopback or
Hostgate on the Express hub, and no production guard: phase 1 of 4: safe by default and wired into your workflow #340. - Requests without
Originare always trusted (needsSec-Fetch-Site): phase 1 of 4: safe by default and wired into your workflow #340. - MCP is tokenless by default in the Vite plugin: phase 1 of 4: safe by default and wired into your workflow #340.
- The MCP token is printed to stdout: phase 1 of 4: safe by default and wired into your workflow #340.
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething is broken or shows wrong dataSomething is broken or shows wrong datafeatureA feature request or a pull request that adds oneA feature request or a pull request that adds one
Activity
fix: audit findings for the panel shell, hub, extension and native ov…