Skip to content

Commit c00c94a

Browse files
authored
Merge pull request #20 from pi0/fix/serialize-key
fix: escape unsafe object keys
2 parents 2da67f8 + 14cae90 commit c00c94a

File tree

2 files changed

+18
-4
lines changed

2 files changed

+18
-4
lines changed

src/index.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
2+
const unsafeChars = /[<>\b\f\n\r\t\0\u2028\u2029]/g;
23
const reserved = /^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/;
34
const escaped: Record<string, string> = {
45
'<': '\\u003C',
@@ -220,12 +221,20 @@ function getType(thing: any) {
220221
return Object.prototype.toString.call(thing).slice(8, -1);
221222
}
222223

224+
function escapeUnsafeChar(c: string) {
225+
return escaped[c] || c
226+
}
227+
228+
function escapeUnsafeChars(str: string) {
229+
return str.replace(unsafeChars, escapeUnsafeChar)
230+
}
231+
223232
function safeKey(key: string) {
224-
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : JSON.stringify(key);
233+
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : escapeUnsafeChars(JSON.stringify(key));
225234
}
226235

227236
function safeProp(key: string) {
228-
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`;
237+
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? `.${key}` : `[${escapeUnsafeChars(JSON.stringify(key))}]`;
229238
}
230239

231240
function stringifyString(str: string) {
@@ -256,4 +265,4 @@ function stringifyString(str: string) {
256265

257266
result += '"';
258267
return result;
259-
}
268+
}

test/test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ describe('devalue', () => {
8888
`</script><script src='https://evil.com/script.js'>alert('pwned')</script><script>`,
8989
`"\\u003C\\u002Fscript\\u003E\\u003Cscript src='https:\\u002F\\u002Fevil.com\\u002Fscript.js'\\u003Ealert('pwned')\\u003C\\u002Fscript\\u003E\\u003Cscript\\u003E"`
9090
);
91+
test(
92+
'Dangerous key',
93+
{ '<svg onload=alert("xss_works")>': 'bar' },
94+
'{"\\u003Csvg onload=alert(\\"xss_works\\")\\u003E":"bar"}'
95+
)
9196
});
9297

9398
describe('misc', () => {
@@ -109,4 +114,4 @@ describe('devalue', () => {
109114
assert.throws(() => devalue({ [Symbol()]: null }));
110115
});
111116
});
112-
});
117+
});

0 commit comments

Comments
 (0)