In JS, the TextEncoder.encode() method takes a string as input, and returns a Uint8Array containing the text given in parameters encoded with the specific method for that TextEncoder object.
When a tainted string is passed to the encode method, the taint is lost. The sample code that can be used to reproduce this bug is found below. pageX and client X are marked as taint sources in this example.
const {pageX, pageY, clientX, clientY, shiftKey} = e;
let item1=[pageX,clientX];
let stringItem= JSON.stringify(item1);
const textEncoder = new TextEncoder();
let encoded = textEncoder.encode(stringItem);
sessionStorage.setItem("smt", JSON.stringify(encoded));
I tracked down the code responsible for the encoding function and it can be seen below.
void TextEncoder::Encode(JSContext* aCx, JS::Handle<JSObject*> aObj,
const nsACString& aUtf8String,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv) {
JSAutoRealm ar(aCx, aObj);
JSObject* outView = Uint8Array::Create(aCx, aUtf8String, aRv);
if (aRv.Failed()) {
return;
}
aRetval.set(outView);
}
Originally I thought that the taint was being lost due to the creation of a Uint8Array, so to test this theory I added a a check above that line to see if aUtf8String is still tainted before entering the create function for Uint8Array. Turns out that aUtf8String is no longer tainted at this point.
I looked further into this issue and found that in the TextEncoder.webidl it mentions the following: "This is spec-wise USVString but marking it as UTF8String as an optimization. (The SpiderMonkey-provided conversion to UTF-8 takes care of replacing lone surrogates with the REPLACEMENT CHARACTER, so the observable behavior of USVString is matched.)". I was able to track down this code to the method JS_PUBLIC_API mozilla::Maybe<std::tuple<size_t, size_t>> JS_EncodeStringToUTF8BufferPartial(JSContext* cx, JSString* str, mozilla::Span<char> buffer) in jsapi.cpp. This method takes a JSString and transforms it to a buffer where the taint is lost.
So what I think is happening is that a JSString gets transformed to a buffer where the taint is lost and that buffer is later transformed to a nsACString.
I think this bug also has bigger implications since I can see many methods that transform JSStrings into types that are not taint aware like the JS_EncodeStringToUTF8 method who transforms JSString to a JS::UniqueChars.
In JS, the TextEncoder.encode() method takes a string as input, and returns a Uint8Array containing the text given in parameters encoded with the specific method for that TextEncoder object.
When a tainted string is passed to the encode method, the taint is lost. The sample code that can be used to reproduce this bug is found below. pageX and client X are marked as taint sources in this example.
I tracked down the code responsible for the encoding function and it can be seen below.
Originally I thought that the taint was being lost due to the creation of a Uint8Array, so to test this theory I added a a check above that line to see if aUtf8String is still tainted before entering the create function for Uint8Array. Turns out that aUtf8String is no longer tainted at this point.
I looked further into this issue and found that in the TextEncoder.webidl it mentions the following: "This is spec-wise USVString but marking it as UTF8String as an optimization. (The SpiderMonkey-provided conversion to UTF-8 takes care of replacing lone surrogates with the REPLACEMENT CHARACTER, so the observable behavior of USVString is matched.)". I was able to track down this code to the method
JS_PUBLIC_API mozilla::Maybe<std::tuple<size_t, size_t>> JS_EncodeStringToUTF8BufferPartial(JSContext* cx, JSString* str, mozilla::Span<char> buffer)in jsapi.cpp. This method takes a JSString and transforms it to a buffer where the taint is lost.So what I think is happening is that a JSString gets transformed to a buffer where the taint is lost and that buffer is later transformed to a nsACString.
I think this bug also has bigger implications since I can see many methods that transform JSStrings into types that are not taint aware like the
JS_EncodeStringToUTF8method who transformsJSStringto aJS::UniqueChars.