Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TextEncoder doesn't propagate the taint #238

Open
alexbara2000 opened this issue Nov 28, 2024 · 0 comments
Open

TextEncoder doesn't propagate the taint #238

alexbara2000 opened this issue Nov 28, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@alexbara2000
Copy link

alexbara2000 commented Nov 28, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants