Skip to content

TextEncoder doesn't propagate the taint #238

@alexbara2000

Description

@alexbara2000

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions