Skip to content

Do not let patch object override the id in updateApiKey - #88

Open
bluzername wants to merge 1 commit into
BitMiracle-AI:mainfrom
bluzername:fix-updateapikey-id-override
Open

Do not let patch object override the id in updateApiKey#88
bluzername wants to merge 1 commit into
BitMiracle-AI:mainfrom
bluzername:fix-updateapikey-id-override

Conversation

@bluzername

Copy link
Copy Markdown

Fixes #76.

What was wrong

updateApiKey build the request body like this:

const data = await this.rpc('updateApiKey', { id, ...patch });

patch is spread after id, so if the patch object also carry an id
field, it win over the real target id. TypeScript do not stop this
because excess-property check only apply to object literals, not to a
variable that is passed in — so a caller can pass a patch variable
that structurally has an id and the compiler stay quiet.

Effect: an admin who mean to edit key A can end up editing key B
instead, with no error, exactly like the repro in the issue.

Fix

Swap the spread order so id always come from the explicit argument,
never from patch:

const data = await this.rpc('updateApiKey', { ...patch, id });

Test

Added updateApiKey ignores an id smuggled inside the patch object in
packages/sdk/src/client.test.ts. It create two real keys over the
in-memory server, call updateApiKey(intended.id, { id: victim.id, disabled: true }),
and check the intended key get disabled while the victim key stay
untouched. This test fail before the fix and pass after.

Also added a changeset (@dormice/sdk patch).

Checked locally

  • pnpm build
  • pnpm --filter @dormice/sdk test — 32 passed (31 before + 1 new)
  • pnpm test (full monorepo) — all green
  • pnpm typecheck and pnpm lint — clean

I am not a native English speaker, sorry for any small mistake in the wording, the code and test should speak clear enough.

The client build the request like this: { id, ...patch }. If someone
pass a patch variable that also have an id field inside (this can
happen because TypeScript only check extra fields on an object
literal, not on a variable), the spread come after and it win. So the
request can go to the wrong key instead of the one you ask for.

Now it build the object as { ...patch, id } so the id argument always
stay the real target, and patch can only touch name, expiresAt and
disabled.

Added a test that create two keys and try to sneak the second key id
inside the patch of the first one. Before the fix this test fail, now
it pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sdk: updateApiKey patch data can override the target ID

1 participant