Skip to content

Attack vector arising from naive developer use of the +layout.server.js tree #6315

@cdcarson

Description

@cdcarson

Describe the bug

tldr;

  • The existence of the +layout.server.js tree will lead folks to put logic there rather than in +page.server.js.
  • Because SvelteKit decides on the client what to fetch from the tree, there are edge cases where important (e.g., authorization) logic in +layout.server.js is skipped.
  • This may seem a contrived edge case, but it is an attack vector that needs to be addressed through documentation.

Consider the following case. (Repo link below)

src
└── routes
    └── launch-codes
        ├── +layout.server.js
        ├── +page.server.js
        └── +page.svelte

Let's say I naively (but I think quite naturally) do the following things:

  • I place authentication/authorization logic in the +layout.server.js file. Perhaps I plan to elaborate this section of the site with launch-codes/[id].
  • Meanwhile, I use +page.server.js to fetch a paged list of codes from the database.

Essentially I have separated the concerns of authorization and data collection.

Now this is totally secure as long as my user remains signed in. But let's say the following happens:

  • The user goes to /launch-codes. This first page view runs the authorization logic in +layout.server.ts.
  • They are signed out, say on another tab, or because the cookie expires, or just by deleting the cookie in the console.
  • In the original tab, now signed out, they go to /launch-codes?page=2. The authorization logic in +layout.server.ts is skipped, and the signed out user is shown the launch codes.

I don't think there's a way to reliably fix this in the framework. The client side router decides what to fetch, and that AFAICT will always be manipulable. The only way to "fix" it is by documentation.

(Or we could get rid of the layout data tree notion entirely. Not a bad option, IMO, but a separate losing argument.)

I know all this may seem contrived, but:

  • It's not that far-fetched for a developer to assume that separating authorization concerns is partly what +layout.server.js is for.
  • It's not that far-fetched to assume that some apps may require quick cookie expiration. Think your bank.
  • It exists. It's an attack vector.

Reproduction

Reproduction here, as minimal as I could make it: https://github.com/cdcarson/yellow-submarine.git

git clone https://github.com/cdcarson/yellow-submarine.git
cd yellow-submarine
npm i
npm run dev
  • Go to http://127.0.0.1:5173/launch-codes
  • Assuming you are not signed in, you'll be redirected to a sign in page, and redirected back after clicking the button
  • Navigate through the paginated list
  • In the tab's console, delete the signedIn cookie. (I.e. the cookie has expired or you've been signed out on another tab.)
  • Without refreshing the page, click to another page in the list. You will be shown that page, rather than being redirected to /sign-in

I made a separate route with a "non-naive" implementation, getting rid of layout.server.js and doing the authorization in +page.server.ts.

Logs

No response

System Info

System:
    OS: macOS 12.4
    CPU: (8) arm64 Apple M1
    Memory: 70.06 MB / 8.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.13.2 - ~/.nvm/versions/node/v16.13.2/bin/node
    npm: 8.1.2 - ~/.nvm/versions/node/v16.13.2/bin/npm
  Browsers:
    Chrome: 104.0.5112.101
    Safari: 15.5
  npmPackages:
    @sveltejs/adapter-auto: next => 1.0.0-next.66 
    @sveltejs/kit: next => 1.0.0-next.442 
    svelte: ^3.44.0 => 3.49.0 
    vite: ^3.0.4 => 3.0.9

Severity

serious, but I can work around it

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions