Skip to content

Form action lookup resolves Object.prototype methods via bracket notation #15525

@FredKSchott

Description

@FredKSchott

Describe the bug

SvelteKit's form action handler uses bracket notation lookup on a plain JavaScript object without prototype safety checks. Submitting a form action with a prototype property name (like ?/toString) resolves to Object.prototype.toString, bypasses the 404 guard, and returns a 200 success response. Other prototype properties like constructor trigger 500 errors.

The issue is in packages/kit/src/runtime/server/page/actions.js at line 246, where actions[name] is used without Object.hasOwn() protection.

Reproduction

Any page with form actions is affected:

# toString bypasses guard and returns 200 success
curl -s -X POST "http://localhost:4173/test-actions?/toString" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Accept: application/json" \
  -H "Origin: http://localhost:4173" \
  -d "test=1"
# Returns: {"type":"success","status":200,"data":"[\"[object Undefined]\"]"}

# constructor bypasses guard but triggers 500
curl -s -X POST "http://localhost:4173/test-actions?/constructor" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Accept: application/json" \
  -H "Origin: http://localhost:4173" \
  -d "test=1"
# Returns: {"type":"error","error":{"message":"Internal Error"}}

# Non-existent action correctly returns 404
curl -s -X POST "http://localhost:4173/test-actions?/nonexistent" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Accept: application/json" \
  -H "Origin: http://localhost:4173" \
  -d "test=1"
# Returns: {"type":"error","error":{"message":"Not Found"}}

Logs

No crash — server continues running. The constructor variant invokes the application's handleError hook.

System Info

System:
  OS: macOS 26.2
  CPU: (14) arm64 Apple M4 Pro
Binaries:
  Node: 24.13.0
  pnpm: 10.28.1
npmPackages:
  @sveltejs/kit: ^2.50.2 => 2.53.4
  svelte: ^5.51.0 => 5.53.7
  vite: ^7.3.1 => 7.3.1

Severity

annoyance

Additional Information

Suggested fix — replace the bracket notation lookup with a prototype-safe check:

// Before (line 246):
const action = actions[name];
if (!action) {
	throw new SvelteKitError(404, 'Not Found', `No action with name '${name}' found`);
}

// After:
if (!Object.hasOwn(actions, name)) {
	throw new SvelteKitError(404, 'Not Found', `No action with name '${name}' found`);
}
const action = actions[name];

The same pattern exists in packages/kit/src/runtime/server/remote.js at three hash lookup sites (lines 44, 207, 259) where remotes[hash] should also use Object.hasOwn(remotes, hash).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions