sveltejs / sveltejs/kit

Form fields go haywire if they match Object.prototype properties

Open Beginner friendly
#17,134 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
20.8k
Forks
2.3k
Avg merge
1d 16h
Merged PRs (30d)
156

Description

Describe the bug

If you have a form like this...

import { form } from '$app/server';
import * as v from 'valibot';

export const myform = form(v.object({
	toString: v.pipe(v.string(), v.minLength(5)),
}), (data) => {
	console.log(data);
});
<script lang="ts">
	import { myform } from './remote';
</script>

<form {...myform}>
	<input {...myform.fields.toString.as('text')} />
	<button>submit</button>
</form>

...two strange things happen. Firstly the input is populated with function toString() { [native code] }, because deep_get doesn't do an Object.hasOwn check:

Image

Secondly, if you delete the text (so that the field is invalid) and submit, an error occurs:

result[name].push is not a function

That's because result inside flatten_issues is a plain object, when it needs to be Object.create(null).

The following patch fixes both issues:

diff --git a/packages/kit/src/runtime/form-utils.js b/packages/kit/src/runtime/form-utils.js
index f2bb444cc8..52cd00d5ce 100644
--- a/packages/kit/src/runtime/form-utils.js
+++ b/packages/kit/src/runtime/form-utils.js
@@ -578,7 +578,7 @@ export function normalize_issue(issue, server = false) {
  */
 export function flatten_issues(issues) {
 	/** @type {Record<string, InternalRemoteFormIssue[]>} */
-	const result = {};
+	const result = Object.create(null);
 
 	for (const issue of issues) {
 		(result.$ ??= []).push(issue);
@@ -610,7 +610,7 @@ export function flatten_issues(issues) {
 export function deep_get(object, path) {
 	let current = object;
 	for (const key of path) {
-		if (current === null || typeof current !== 'object') return undefined;
+		if (current === null || typeof current !== 'object' || !Object.hasOwn(current, key)) return undefined;
 		current = current[key];
 	}
 	return current;
Reproduction

see above

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/kit/src/runtime/form-utils.js at flatten_issues and deep_get, using the supplied form reproduction as the first check. Done means fields named after Object.prototype properties no longer receive inherited values and invalid submissions no longer trigger the reported error; run the relevant form tests or reproduction to verify both cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
full-stack
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.