CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Can cleaning a key change what Object.assign does with it?
Yes in our isolated fixtures. Repairing __proto__ makes Object.assign change the fresh target’s prototype; object spread creates an own property instead. The global Object.prototype stays unchanged.
Open the Claude text cleaner · Full measured data
Measured inputs and outputs
These are locally constructed test strings, not evidence that Claude inserts these characters. We executed the saved homepage script snapshot with a minimal DOM harness and compared exact strings. The invisible-checkbox state and dash mode appear in each row. The observations below test this page's specific question. Destination observations run independently on the exact input and cleaned strings in the recorded Node runtime. We make no detector-score or statistical-watermark removal claim.
| Fixture and mode | Input string and code points | Output and cleaner status | Observed before / after |
|---|---|---|---|
| Marked special key direct string / keep / invisible true | "__proto__"U+005F U+005F U+0070 U+0072 U+006F U+200B U+0074 U+006F U+005F U+005F | "__proto__"Removed 1 invisible character | {"sourceOwn":true,"assignedOwn":true,"assignedPrototypeFlag":false,"spreadOwn":true,"spreadPrototypeFlag":false,"globalPrototypeFlag":false}{"sourceOwn":true,"assignedOwn":false,"assignedPrototypeFlag":true,"spreadOwn":true,"spreadPrototypeFlag":false,"globalPrototypeFlag":false} |
| Plain special key direct string / keep / invisible true | "__proto__"U+005F U+005F U+0070 U+0072 U+006F U+0074 U+006F U+005F U+005F | "__proto__"No selected invisible characters found | {"sourceOwn":true,"assignedOwn":false,"assignedPrototypeFlag":true,"spreadOwn":true,"spreadPrototypeFlag":false,"globalPrototypeFlag":false}{"sourceOwn":true,"assignedOwn":false,"assignedPrototypeFlag":true,"spreadOwn":true,"spreadPrototypeFlag":false,"globalPrototypeFlag":false} |
| Ordinary property direct string / keep / invisible true | "label"U+006C U+0061 U+0062 U+0065 U+006C | "label"No selected invisible characters found | {"sourceOwn":true,"assignedOwn":true,"assignedPrototypeFlag":false,"spreadOwn":true,"spreadPrototypeFlag":false,"globalPrototypeFlag":false}{"sourceOwn":true,"assignedOwn":true,"assignedPrototypeFlag":false,"spreadOwn":true,"spreadPrototypeFlag":false,"globalPrototypeFlag":false} |
| Retained joiner direct string / keep / invisible true | "__proto__"U+005F U+005F U+0070 U+0072 U+006F U+200D U+0074 U+006F U+005F U+005F | "__proto__"No selected invisible characters found | {"sourceOwn":true,"assignedOwn":true,"assignedPrototypeFlag":false,"spreadOwn":true,"spreadPrototypeFlag":false,"globalPrototypeFlag":false}{"sourceOwn":true,"assignedOwn":true,"assignedPrototypeFlag":false,"spreadOwn":true,"spreadPrototypeFlag":false,"globalPrototypeFlag":false} |
The same own source key reaches two different targets
The source is constructed through JSON serialization and parsing so the tested spelling is an own data property, with an invented object value containing fixtureFlag. Before deletion the interrupted spelling is copied as an ordinary own key by both operations. After repair, Object.assign into a fresh empty object has no own __proto__ property and its prototype carries our flag. The spread target has the own property and an unchanged ordinary prototype. The plain special-key control repeats this difference without cleaning. The label control and retained joiner stay ordinary properties. Every row also records that Object.prototype itself has no fixtureFlag, delimiting the effect to the authored target.
Cleanup changes spelling while the copy operation supplies behavior
The homepage never constructs these objects and does not perform the copy. The observer deliberately contrasts assignment semantics with creation of own properties. This is a different problem from JSON duplicate members, where parsing selects a surviving value, and from Map.set, where an equal key overwrites a payload. Here a repaired spelling meets destination behavior even though the source owns it. We use fresh local objects for each stage; no production configuration, request body, external system or global prototype is modified. These fixtures are a small diagnostic comparison and do not establish the security properties of a complete application, recursive merge library or framework.
Validate key policy at the destination boundary
Keep original and repaired key spellings together and validate them against the destination’s permitted schema before copying untrusted data. Confirm whether the chosen operation creates own properties or invokes target behavior, rather than assuming a parsed JSON property is harmless everywhere it travels. A removal count is not a schema check. Our downloads report ownership, target prototype observations and the unchanged global control for all four inputs. They do not provide a universal sanitizer or prove that spread alone solves every data-validation problem. Choose the intended copy and validation policy for the actual application, retain the original payload, and rerun destination-specific checks after any character edit.
Reproduce this test
Save reproduce.cjs and tested-app.js in the same folder. Run the command below with Node.js. The harness prints its runtime, script SHA-256 and every measured row. Compare those rows with the original record. Using a newer script or runtime creates a new experiment; retain the version information with your rerun.
node reproduce.cjsReference and next check
ECMAScript Object.assign provides the relevant primary definition. The table and fixture analysis are original measurements. For broader inspection, use our Unicode inspector. Read the scope distinction before interpreting cleanup as a watermark result.