cross-posted from: https://lemmy.world/post/49778353

Also /c/modabuse. Also /c/yepowertrippinbastards. Also lemmy.ml/c/worldnews, comrade, ACAB, and 552 individual accounts across 67 instances, about half of them on lemmy.world.

None of this is in the source code. It’s downloaded at runtime from a file nobody has ever looked at.

If you’re just tuning in

Tesseract is a third-party web frontend for Lemmy, maintained by asimons04 and licensed AGPL-3.0. Admins deploy it on their own servers alongside or instead of lemmy-ui, and there are public instances of it people use to browse Lemmy generally. If you’ve used a Lemmy site that didn’t look like stock Lemmy, there’s a fair chance it was this.

Last week db0 posted a PSA: Tesseract contains a blacklist of instance domains compiled directly into the application. 32 of them. Admins can’t see it, can’t configure it, and aren’t told it’s there. Connect to a listed instance and the app tells you it’s “incompatible,” which is not true.

I went through the code to see how that was implemented. The hardcoded list turns out to be the small half of the system.

There’s a second filter policy fetched over HTTP every time the app loads. It isn’t in the git repository. It’s unauthenticated and world-readable, so anyone can pull it. Right now it carries 552 user accounts, 2,275 username patterns, 54 instances, 97 communities, 289 keyword patterns and 351 domains, with every category set to hide matches rather than flag them. Not collapsed behind a click. Simply absent, with no indication anything was removed.

Verify all of it in ten seconds

curl -s https://tesseract.dubvee.org/tesseract/api/system/policy \
  | base64 -d | gunzip > policy.json

That’s the live policy, base64-wrapped gzip, 111KB of JSON when it unpacks. There’s a stale fallback copy at /data/policy.dat as well.

It filters criticism of moderators

  • lemmy.sdf.org/c/modabuse — listed
  • lemmy.dbzer0.com/c/yepowertrippinbastards — listed
  • lemmy.dbzer0.com/c/YPTBcirclejerk — listed
  • community regex power ?tripping?
  • keyword censoring me

Call the rest of it whatever you like. This part is not spam defence.

It filters words

The 32 community name patterns include Communis(t|m), Conservativ(e|es|ism), Leftis(t|m), Libertarian(ism)?, ^Green Part(y|ies), Zionis(t|m), (Police|Cops), guillotine and billionaire.

Keywords include comrade, ACAB, neoliberal, proletaria(n|t) and death to.

Filtered communities on instances that aren’t blocked: lemmy.ml/c/worldnews, lemmy.today/c/news, lemmy.ca/c/politicalnewscanada, lemmy.ca/c/usa, infosec.pub/c/strategic_unions.

The 552 users aren’t bots

67 instances. 272 on lemmy.world alone, 40 on sh.itjust.works, 19 on lemmy.ca, and 28 instances contributing exactly one person each.

355 of the 552 usernames are plain alphabetic, twelve characters or under, median length eight. Only 36 look like spam registrations. A bot list looks like the opposite of that.

Seven of them aren’t even Lemmy. There are Mastodon and Friendica accounts in there: people who have never used Lemmy, hidden by a Lemmy frontend, with no possible way of finding out.

I have the list and I’m not posting it. Most of these are ordinary people who got pattern-matched, and 552 names on this comm is a harassment target inside an hour. Run the command above and grep for yourself.

And it lies about it

When the instance block fires you get: “Incompatible Instance. Not Supported. $instance is not compatible with Tesseract.”

Nothing is incompatible. It’s a policy decision dressed as an API error, and it’s what had db0 chasing a version mismatch that never existed.

For the hidden users, communities and keywords, you get no message at all.

Admins can’t switch it off

Tesseract has env vars for PUBLIC_DOMAIN_BLACKLIST, PUBLIC_FAKE_NEWS_BLACKLIST and the shortener lists. There is none for either blocklist. enableToxicMode bypasses the other filters and explicitly not this one.

Self-host it and you cannot disable this, nothing in your config admits it exists, and the contents can change without you pulling a commit.

Before someone says it

A lot of that domain list is real spam defence. It filters conservatism as well as communism. “It targets the left” doesn’t survive the data and I’m not going to pretend it does.

The problem is that spam filtering and political editorial got welded into one undocumented, remotely-updatable blob, shipped hidden, to admins who’ve never read it and users who don’t know it’s there. The spam work is what makes the rest unauditable: “it’s a spam list” answers every individual question and none of the whole.

And /c/modabuse is not spam.

Asks

  1. Publish the runtime policy in the repo, or kill the endpoint.
  2. Stop reporting a policy block as a technical incompatibility.
  3. Tell users when something’s been hidden. One line.
  4. Give operators an off switch, like every other blacklist in the codebase has.

It’s AGPL-3.0 and db0 already forked it. That’s the licence working as designed. But forking isn’t disclosure, and the admins who need this are precisely the ones with no reason to go looking.

If you run Tesseract, you are relaying a 111KB moderation policy you have never read, under your instance’s name, to users who don’t know it exists.

Full contents of every list, unedited, in the comments.

  • bamboo@lemmy.blahaj.zone
    link
    fedilink
    English
    arrow-up
    54
    ·
    1 day ago

    I took a look at it earlier today and the addition of instances to be blocked was super shady and sloppy on part of the maintainer. Some high profile instances were added to the blocklist alongside unrelated changes and not mentioned in the git commit message, for example this commit: https://github.com/asimons04/tesseract/commit/fcd71e01e9f64d5ff40dbee9b815971bc00e9a2a

    Also apparently the error you’d get when going to the blocked instance was a generic error which makes the user think there’s a network issue or incompatibility with the API or something and the idea of a hard coded blocklist is never presented to the user as the source of the issue.

    • Zarobi@aussie.zone
      link
      fedilink
      English
      arrow-up
      6
      ·
      19 hours ago

      That Github is a fun read in general. Some of these variables and function names are sending me. They even seem to be blocking proton email addresses.

      Tap for blacklists.ts

      https://github.com/asimons04/tesseract/blob/main/src/lib/blacklists.ts

      My personal highlights:

      
      // Domains that have been identified as frequent spam
      export const SPAM_SITES = [
          'gofund.me',
          'gofundme.com',
      
      // ...
      
      const SHIT_KNOWN_BAD_LEMMY_ACTORS_SPAM
      
      // ...
      
      // Very non-comprehensive list of domains that host disposable/temporary/throwaway email aliases. Basically just the low-hanging fruit to aid in decision making.
      export const THROWAWAY_EMAIL_DOMAINS = [
          'proton.me',
          
      // ...
      
      export const BLACKLISTED_INSTANCES: string[] = [
              "abolish.capital",
              "altmedia.house",
              "anarchist.nexus",
              "chapo.chat",
              "chatgptjailbreak.tech",
              "diggita.com",
              "hexbear.com",
      		"hexbear.net",
              "ibbit.at",
              "test.hexbear.net",
              "www.hexbear.net",
              "hilariouschaos.com",
              "lemmy.bestiver.se",
              "lemmy.blahaj.zone",
              "lemmy.dbzer0.com",
              "lemmy.doesnotexist.club",
              "lemmy.durstig.online",
              "lemmy.ml",
              "lemmy.razbot.xyz",
              "lemmybefree.net",
              "lemmygrad.ml",
              "lemmyusa.com",
              "lemy.lol",
              "maga.place",
              "multiverse.soulism.net",
              "news.abolish.capital",
              "nnia.space",
              "noauthority.social",
              "r.nf",
              "realbitcoin.cash",
              "redlemmy.com",
              "welppp.com"
      ]
      
      // ...
      
      // Fake news sites that MBFC doesn't have on file or are known disinformation campaignss
      export const FAKE_NEWS = [
          ...RUSSIAN_GRU_INFOROS,
          ...RUSSIAN_NEWS_DOPPLEGANGER,
          ...RUSSIAN_OPERATION_UNDERCUT,
          ...RUSSIAN_PORTAL_KOMBAT_PRAVDA_NETWORK,
          ...RT_ALIASES,
          ...STOP_NEWS,
          ...OTHER_RUSSIAN_CAMPAIGNS,
          ...JOHN_MARK_DOUGAN,
          ...SHIT_KNOWN_BAD_LEMMY_ACTORS_SPAM,
          ...MAGA_PROPAGANDA,
      
          // Admin-extended list from env vars
          ...BLACKLIST_CONFIG.FAKE_NEWS_BLACKLIST
      ]
      
      // ...
      
      export const isFakeNewsSite()
      
      // ...
      
          if ( get(userSettings).enableToxicMode) return false
          
      
      Tap for filtering.ts

      https://github.com/asimons04/tesseract/blob/main/src/lib/filtering.ts

      They seem to be filtering out a lot of political keywords!

      // Initialize a default blank policy
      export const defaultFilterPolicy: FilterPolicy = {
          name: 'Default Policy',
      
          communityRegexes: [
              "^Ban ",
              "^Boycott",
              "(Elon|(Elon )?Musk)",
              "^Fuck",
              "Palestine",
              "Iran",
              "Israel",
              "Musk",
              "^News|News$",
              "^Politic(a|s|al)|^Politik",
              "Trump",
          ],
          communityInstances: [
              "ani.social",
              "pawb.social"
          ],
      
      Tap for data.json

      https://raw.githubusercontent.com/asimons04/tesseract/refs/heads/main/src/lib/MBFC/data/data.json

      Some juicy comments in this one. It’s a list of news sources with their “bias” (left/right/centre/etc). They didn’t write this, they copied it from https://github.com/drmikecrowe/mbfcext/blob/main/docs/v5/data/combined.json

      “Official Media Bias/Fact Check Extension”

      Be informed as you read your Facebook feed. We are the most comprehensive media bias resource on the internet. There are currently 1100+ media sources listed in our database and growing every day. Don’t be fooled by Fake News sources. This extension is completely open source, and the source code is hosted here.

      politico.com
      bbc.com
      cbsnews.com
      front.moveon.org
      
      These media sources are moderately to strongly biased toward liberal causes
      
    • Carl@anarchist.nexus
      link
      fedilink
      English
      arrow-up
      59
      ·
      edit-2
      1 day ago

      Some high profile instances were added to the blocklist alongside unrelated changes and not mentioned in the git commit message… Also apparently the error you’d get when going to the blocked instance was a generic error…

      Yeah, the combination of those two issues are exactly why the hidden blocklist was noticed in the first place. The site admin for db0 noticed that their frontend was broken after they updated their Lemmy stack. But the “incompatible” version of Lemmy they had just updated to was supported. So what was causing the incompatibility? Maybe an API issue? Nope, API is fine.

      After some digging, they eventually realized that it was happening due to an instance block at the frontend’s level. But they didn’t have their own instance blocked in the frontend, so why was it being blocked? Turns out, it was because they were previously running an old version of Tesseract from before the blocklist was implemented. When they updated their stack (which also updated Tesseract), the new version suddenly included the hidden blocklist code. So when they tried to start their stack after updating, the new version of Tesseract quietly downloaded the hidden blocklist (which can’t be disabled) and blocked the instance it was currently running on. This effectively broke the frontend for db0, which is what led to the investigation and subsequent hidden blocklist discovery.