Repository navigation
fix(plugins): storage paths can't reach Object.prototype, increment respects the key cap, proxy redirects stay on the whitelist - #319
Conversation
…espects the key cap, proxy redirects stay on the whitelist Reported in mrramam#54, #60 and #56. - Storage increment walked a caller's dot-path with no filtering, so `__proto__.x` (from the route or a manifest reaction) wrote onto Object.prototype in the server process. Paths with __proto__, constructor or prototype segments are refused (400) by the route, by manifest validation and by the increment itself, which now steps only through own properties. - Increment created keys without counting them, skipping the 500-key cap PUT enforces. A new key now counts, inside the same transaction (413). - /api/proxy checked only the first address, then followed up to five redirects anywhere, so a whitelisted host could send it to an address on the household's network. Every hop is now checked against the whitelist (403 when one leads off it), and only http(s) is fetched. - GitHub install fetched any download_url and echoed the upstream body on errors. It now takes only files in jherforth/HomeGlowPlugins on raw.githubusercontent.com (the addresses the listing gives), follows no redirects, and no longer echoes what came back. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
One gap in the GitHub install check: |
Review of #319 (Mrramam): the check ran startsWith on the raw string, but the URL is normalized when it's fetched, so ".../HomeGlowPlugins/%2e%2e/%2e%2e/<someone>/<repo>/main/x.html" passed and loaded another repository's file. The address is now parsed first: https on raw.githubusercontent.com, no user name or password, and a normalized path inside /jherforth/HomeGlowPlugins/. Encoded dots, slashes and backslashes are refused, so nothing can decode into a different path later. The normalized address is the one fetched and recorded. Real listing addresses (nested folders, %20 in a name) still pass. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
The GitHub install check could be bypassed with an encoded .. in the address, loading another repo's file. It stayed on GitHub, so it was no route into the home network. |
Adds the 1.10 changelog covering everything merged since v1.9.1 (#211 to #319): themes as installable packages and weather scenes, Home Assistant panels and music, Routines in the core, expiring and follow-up chores, phone notifications (browser, ntfy, the Home Assistant app), backup and restore, wall-display touches, the plugin store's versions and categories, and a round of security fixes. Credits to @mrramam, @adamecker and @jasonstantler, and upgrade notes: back up first, reinstall Reef or Starship from the theme store, the Routines plugin moves into the core by itself, and the plugins repository's folder layout follows this release. Versions bumped to 1.10.0 in both package.json files and their lockfiles. The About tab reads its version from the git tag at build time, so the v1.10 tag is what users will see; these keep local runs honest. Co-authored-by: Claude Opus 5.5 <[email protected]>
…e 1.10 jherforth#321, plugin storage/proxy fixes jherforth#319, chore timezone display jherforth#318, CI pins jherforth#316-317, prize descriptions jherforth#315, proxmox/docker fixes jherforth#314, plugin proxy docs jherforth#313, Google OAuth escaping jherforth#312, upload typing/sandbox jherforth#311 Resolve registry conflict: keep fork renumbering (local 28 userGoogleTasks, 34 googleTasksTables); upstream's new 35 proxyWhitelistSeed and 36 prizeDescription renumbered to 41 and 42 to keep schemaIds unique and matching file names.
Fixes four plugin-reachable problems from Mrramam's audit: mrramam#54, #60 and two parts of #56. These are the ones that don't depend on the plugin-isolation work (#50, #49), which is coming as its own change.
Fixes
Object.prototype(feat: multi-tenancy #54). The increment walked the caller's dot-path with no filtering. A__proto__.xpath, fromPOST …/incrementor a manifest reaction, therefore wrote ontoObject.prototypefor the whole server process.__proto__,constructororprototypeare now refused with400. The route, manifest validation and the increment function itself all check this.PUTcounted keys,incrementdidn't. A new key now counts against the cap inside the same transaction, and over the cap it answers413./api/proxychecked only the first address, then followed up to five redirects anywhere. A whitelisted host could therefore send it to an address on the household's network.beforeRedirect. A redirect off the list answers403, and the off-list host is never contacted.http(s)addresses are fetched.download_urland echoed the upstream body on errors.jherforth/HomeGlowPluginsonraw.githubusercontent.com. These are the only addresses the listing gives.Not in this PR
Plugin isolation, and the open CORS behind it: #50, #49 and the CORS part of #62. While plugins run same-origin and the API allows any origin, a plugin can still call every route directly. That fix changes how all plugins run, so it comes separately.
Testing
npm test: 609 pass. New tests cover each of these cases:__proto__andconstructor.prototypepaths are refused, and nothing is stored;413, while an existing key still works;ftp:address is refused;🤖 Generated with Claude Code