10 interesting stories served every morning and every evening.

GitHub - mysk-research/loupe: A privacy-focused iOS app that raises awareness about what native apps can see

github.com

Loupe is an iOS and iPa­dOS app that gives you a hands-on tour of the de­vice fin­ger­print­ing sur­face. It reads real val­ues from pub­lic iOS APIs, the same ones any third-party app can call, and shows them to you raw. The point is sim­ple: see what your iPhone qui­etly ex­poses, and why each read­ing helps an app rec­og­nize you again.

Trackers don’t need your name, email, or lo­ca­tion to rec­og­nize you on­line. Each read­ing is­n’t nec­es­sar­ily unique on its own, but to­gether they form a fin­ger­print that fol­lows you across apps and web­sites.

How sig­nals are or­ga­nized

Loupe groups every read­ing into three tiers, re­flect­ing the cost of ac­cess:

Passive — vis­i­ble to any app with no prompt at all (locale, time zone, screen, bat­tery, and more).

Needs Permission — read­ings that trig­ger an iOS prompt (contacts, pho­tos, lo­ca­tion, cal­en­dars).

Advanced — clever side-chan­nel uses of pub­lic APIs, such as URL-scheme prob­ing via canOpenURL and Keychain per­sis­tence across re­in­stalls.

Privacy

Nothing Loupe reads leaves your de­vice un­less you ex­plic­itly ex­port it. Values are shown raw, with­out ag­gre­ga­tion or hash­ing. Nothing is up­loaded, synced, or shared.

A note on how this was built

Loupe was writ­ten al­most en­tirely by AI cod­ing tools.

Building

You’ll need Xcode 26 or newer.

Open code/​Loupe.xcode­proj.

Copy code/​Con­fig/​Sign­ing.lo­cal.xc­config.ex­am­ple to code/​Con­fig/​Sign­ing.lo­cal.xc­config and fill in your own DEVELOPMENT_TEAM and bun­dle iden­ti­fiers. This file is git­ig­nored and never pub­lished.

Build and run on a de­vice or sim­u­la­tor.

The pro­ject uses Xcode’s build­able fold­ers (folder ref­er­ences), so new Swift files are picked up au­to­mat­i­cally with no need to edit the pro­ject file.

ma­cOS

Loupe also builds for ma­cOS. The Mac ver­sion is mostly com­plete, but a few things still need work be­fore it’s pol­ished.

Support the pro­ject

Loupe is free and open source. If it helped you see what apps can qui­etly learn about your de­vice, the best way to sup­port more work like this is to try Psylo, our pri­vacy-first browser for iPhone and iPad. Psylo gives you proxy-backed brows­ing, iso­lated tabs, and anti-fin­ger­print­ing pro­tec­tions.

You can also read why we built Psylo.

License

The source code is re­leased un­der the MIT License.

The Loupe name and logo, the app icon, all other im­ages and icons, and the de­sign source files are © Mysk, all rights re­served, and are not cov­ered by the MIT li­cense.

About

Loupe is made by Mysk.

Website

Blog

X

Mastodon

Blocked

old.reddit.com

whoa there, pard­ner!

Your re­quest has been blocked due to a net­work pol­icy.

Try log­ging in or cre­at­ing an ac­count here to get back to brows­ing.

If you’re run­ning a script or ap­pli­ca­tion, please reg­is­ter or sign in with your de­vel­oper cre­den­tials here. Additionally make sure your User-Agent is not empty and is some­thing unique and de­scrip­tive and try again. if you’re sup­ply­ing an al­ter­nate User-Agent string, try chang­ing back to de­fault as that can some­times re­sult in a block.

You can read Reddit’s Terms of Service here.

If you think that we’ve in­cor­rectly blocked you or you would like to dis­cuss eas­ier ways to get the data you want, please file a ticket here.

When con­tact­ing us, please in­clude your Reddit ac­count along with the fol­low­ing code:

019eea62 – 7613-7ff7-a698 – 85c31e074bc3

Beyond All Reason ★ RTS

www.beyondallreason.info

Real-Time Strategy

Redefined

Every unit, pro­jec­tile and ex­plo­sion sim­u­lated in real-time

Unmatched

Scale & re­al­ism

All units and pro­jec­tiles are sim­u­lated in real-time. The game of­fers fully sim­u­lated pro­jec­tile bal­lis­tics, ex­plo­sion physics and ter­rain de­for­ma­tion.

Enjoy an im­mer­sive RTS ex­pe­ri­ence, whether you are com­mand­ing in­di­vid­ual units, or armies of thou­sands. Take con­trol as you en­gage in an epic strug­gle for dom­i­na­tion!

ScreenshotsGameplay

Strategic

Importance of ter­rain

The shape of every bat­tle­field in-game im­poses which strate­gies work and which units are ef­fec­tive. No two maps will play the same. Radar can­not pen­e­trate moun­tains and nu­clear war­fare will phys­i­cally al­ter the ter­rain.

Utilize over 10 dif­fer­ent unit classes, in­clud­ing all-ter­rain Experimental units, to work your way to vic­tory.

Learn how to Play

Countless

World-class con­trols

Your power lies in the care­ful bal­ance of ex­po­nen­tially grow­ing your re­source in­come and the pro­duc­tion of dev­as­tat­ing war ma­chines.

You de­cide if you want to dis­arm your en­e­mies with a few pre­cise early strikes or to build a thou­sand bombers and oblit­er­ate them.

Immerse your­self in a vi­o­lent world where tac­ti­cal and strate­gi­cal su­premacy are needed in your fight to­wards vic­tory.

Commands Overview

Relentless game de­sign

Unique and with a pur­pose

Each and every unit in the game has a role to fill. Mix-and-match units to cre­ate in­fi­nite pos­si­ble tac­tics. Experiment with your own com­bi­na­tions and show off the new strate­gies you de­velop in bat­tle.

Compare Units

Just a moment...

www.cell.com

Google hits 50% IPv6 | APNIC Blog

blog.apnic.net

You may have seen head­lines not­ing that Google’s mea­sure­ments have shown IPv6 reach­ing 50% for the first time. These mea­sure­ments are based on Google’s con­tin­u­ous mon­i­tor­ing of the avail­abil­ity of IPv6 con­nec­tiv­ity among its users, and re­flect the pro­por­tion of users who ac­cess Google ser­vices over IPv6. Reaching the 50% mark is a sig­nif­i­cant mile­stone, demon­strat­ing that IPv6 is a ma­ture, fully ca­pa­ble pro­to­col that is be­ing de­ployed at a global scale and used ef­fec­tively in real-world net­works.

The shape of IPv6 adop­tion is­n’t evenly dis­trib­uted

The global up­take of IPv6 fol­lows a com­plex and var­ied path that is­n’t ap­par­ent in a sin­gle, ag­gre­gated trend line. Google does not pub­lish per‑re­gion IPv6 sta­tis­tics, and its per‑econ­omy data is lim­ited to over­all to­tals, so these nu­ances are hard to see in Google’s fig­ures alone. To un­der­stand how adop­tion re­ally un­folds, it’s more in­struc­tive to look at the APNIC Labs data. Individual economies such as India, Viet Nam, and Saudi Arabia ex­hibit adop­tion curves that dif­fer markedly from the global av­er­age. As the APNIC Labs data shows, this global trend does not nec­es­sar­ily re­flect the ex­pe­ri­ence of in­di­vid­ual economies.

APNICs own mea­sure­ment records a 42% world­wide IPv6 ca­pa­bil­ity (Figure 2). That’s a sub­stan­tial dif­fer­ence, which also needs clar­i­fy­ing.

Measurement dif­fer­ences

APNICs mea­sure­ment pro­gram is run by APNIC Labs and uses on­line ad­ver­tis­ing dis­trib­uted through Google Ads, which ap­pear in end users’ web browsers, games, and apps wher­ever Google ad­ver­tise­ments are placed. APNIC does not se­lect spe­cific users and seeks the broad­est pos­si­ble ex­po­sure in every econ­omy, 24/7. Normal ad­ver­tis­ing track­ing sys­tems are used with APNIC Labs logic, which en­sures a unique set of tests are run, mea­sur­ing IP, BGP rout­ing and DNS, amongst other tech­nol­ogy choices. No end-user Personally Identifiable Information (PII) data is held, and raw mea­sure­ments are never shared, only col­la­tions at the ISP, econ­omy and re­gion level.

This work is car­ried out with the as­sis­tance of Google Research, ICANN, and oth­ers who help fund and sup­port the ac­tiv­ity. Given this close in­volve­ment, it’s nat­ural to ask why APNICs mea­sure­ment re­sults don’t al­ways align with Google’s own pub­lished sta­tis­tics. If Google is used to con­duct the re­search, how can the re­sults dif­fer?

APNICs mea­sure­ment ap­proach ap­plies sta­tis­ti­cal weight­ing to the col­lected data and uses ex­ter­nal sources, such as World Bank sta­tis­tics, to model Internet us­age by econ­omy. This is nec­es­sary be­cause the num­ber of mea­sure­ment sam­ples APNIC Labs re­ceives each day is not uni­form. Advertising place­ments are op­ti­mized by Google to max­i­mize de­liv­ery and rev­enue, which means that, on any given day, more ad­ver­tise­ments, and there­fore more mea­sure­ment sam­ples, may be shown in cer­tain economies than oth­ers. For ex­am­ple, if ad­ver­tis­ing de­mand is higher in North African economies such as Egypt or Tunisia on a par­tic­u­lar day, more mea­sure­ments will be col­lected there, while fewer may be gath­ered from South America or Asia.

As a re­sult, the raw sam­ple counts can­not sim­ply be ag­gre­gated to cal­cu­late global IPv6 ca­pa­bil­ity. Instead, APNIC Labs ag­gre­gates the mea­sured IPv6 ca­pa­bil­ity for each econ­omy and then weights it ac­cord­ing to that econ­o­my’s es­ti­mated Internet user pop­u­la­tion.

In prac­tice, this means that large Internet pop­u­la­tions, such as those in India, China, Indonesia, and other ma­jor economies, con­tribute pro­por­tion­ally more to the global re­sult than smaller economies, even if the raw sam­ple vol­umes on a given day might sug­gest oth­er­wise. This weight­ing en­sures that the fi­nal mea­sure­ments re­flect global Internet us­age more ac­cu­rately, rather than daily ad­ver­tis­ing dis­tri­b­u­tion pat­terns.

At the level of in­di­vid­ual economies, APNIC Labs’ mea­sure­ments gen­er­ally align with the to­tals pub­lished by Google and with data from Cloudflare, Akamai, Cisco, and oth­ers. This sug­gests that the un­der­ly­ing mea­sure­ments are com­pa­ra­ble and that the larger dif­fer­ences ob­served at the global level are likely due to dif­fer­ences be­tween APNICs weight­ing model. This may be why we see the large vari­ances be­tween the two mea­sure­ments.

In prac­tice, APNICs mea­sure­ments tend to be lower than Google’s. As a re­sult, it’s use­ful to view the two data sets to­gether, as they ef­fec­tively bracket the likely range of ac­tual IPv6 ca­pa­bil­ity at any given point in time.

Is IPv6 adop­tion pro­gress­ing as ex­pected?

Some point to the long path to­ward a 50% adop­tion mile­stone as ev­i­dence of a sys­temic fail­ure in IPv6. Nothing could be fur­ther from the truth. Deploying IPv6 has re­quired sub­stan­tial tech­ni­cal ef­fort and sig­nif­i­cant cap­i­tal in­vest­ment. It’s there­fore en­tirely ex­pected that progress has var­ied across re­gions and economies, as in­di­vid­ual ISPs and economies make their own de­ci­sions about how best to bal­ance net­work growth, user ex­pec­ta­tions, and the prac­ti­cal re­al­i­ties of op­er­at­ing Internet in­fra­struc­ture.

The global Internet is not a command econ­omy‘, it evolves through col­lab­o­ra­tion and co­op­er­a­tion within mar­ket-dri­ven con­di­tions. Many providers made sub­stan­tial cap­i­tal in­vest­ments in IPv4 in ear­lier pe­ri­ods and have nat­u­rally sought to max­i­mize the re­turn on those in­vest­ments. In do­ing so, they built sus­tain­able and com­mer­cially vi­able IPv4-based net­works within their ex­ist­ing foot­prints.

By con­trast, for newer mar­ket en­trants, it has of­ten been more ra­tio­nal to adopt IPv6 as the pri­mary pro­to­col, as it can demon­stra­bly re­duce the to­tal cost of own­er­ship. This pat­tern is par­tic­u­larly ev­i­dent in the mo­bile sec­tor, most no­tably in large-scale IPv6 de­ploy­ments such as Reliance Jio’s net­work in India.

Is the global Internet func­tion­ing in a two‑protocol world’?

Yes, but it could be sim­pler.

Certainly, it would be eas­ier lo­gis­ti­cally to run a global in­ter­net un­der a sin­gle pro­to­col. However, that is not the en­vi­ron­ment we have ended up with. Instead, the Internet to­day op­er­ates across a mix of di­rect IPv4 con­nec­tiv­ity, IPv4 me­di­ated through Network Address Translation (NAT), ei­ther in home net­works or at the car­rier level via Carrier‑Grade NAT (CGNAT), and IPv6.

Managing ad­dress trans­la­tion through NAT is not ma­te­ri­ally less com­plex than al­ter­na­tives such as pro­to­col trans­la­tion, IPv4 en­cap­su­la­tion over IPv6, or other tran­si­tion and proxy mech­a­nisms. As a re­sult, claims that IPv4 is work­ing fine’ of­ten over­look the un­der­ly­ing re­al­ity: Modern IPv4 net­works al­ready rely on lay­ers of op­er­a­tional com­plex­ity, and there is no in­her­ently lower‑cost or sim­pler ap­proach avail­able within IPv4 alone.

From the out­set, it was un­der­stood that the lack of di­rect in­ter­op­er­abil­ity be­tween IPv4 and IPv6 would be a chal­lenge that needed to be ad­dressed. Early ef­forts ex­plored the idea of pro­to­cols that could sub­sume IPv4 un­changed and en­able di­rect con­nec­tiv­ity across both worlds, but these ap­proaches did not prove vi­able.

Instead, in­ter­op­er­abil­ity has emerged at higher lay­ers, with trans­port pro­to­cols such as TCP, UDP, and QUIC op­er­at­ing in­de­pen­dently of the un­der­ly­ing IP ver­sion. This model nec­es­sar­ily re­lies on some form of in­ter­me­di­ary. This is vis­i­ble in the way large con­tent and caching providers, such as Cloudflare, are able to of­fer dual‑stack ser­vices re­gard­less of whether the back­end sys­tems them­selves sup­port both pro­to­cols.

The ab­sence of na­tive dual‑stack ca­pa­bil­ity at some ser­vices, for ex­am­ple, cer­tain Git plat­forms or na­tional tele­vi­sion broad­cast­ers, is of­ten per­ceived as a ma­jor bar­rier to IPv6 progress. However, this may re­flect prag­matic con­straints, such as op­er­a­tional com­plex­ity, or, in the case of na­tional broad­cast­ers, le­gal and reg­u­la­tory re­quire­ments around data ac­cess and ge­olo­ca­tion, rather than re­sis­tance.

Let’s rec­og­nize the 50% mile­stone, even as the jour­ney con­tin­ues

Whatever one’s view on the de­ci­sion to in­tro­duce a sec­ond ad­dress­ing and pro­to­col model be­neath to­day’s Internet ser­vices, the re­al­ity is clear: IPv6 is now de­ployed on a global scale. Around half of the Internet users vis­i­ble to Google al­ready reach its ser­vices over IPv6. IPv6 is used every day, every hour, across de­vel­oped and de­vel­op­ing economies alike, on fixed and mo­bile net­works, on small per­sonal de­vices, and within vast data‑cen­tre‑backed ser­vices. It is no longer ex­per­i­men­tal or mar­ginal; it is part of the Internet’s day‑to‑day op­er­a­tion.

That achieve­ment re­flects the col­lec­tive ef­fort of those work­ing to build, op­er­ate, and grow the Internet world­wide, and it is some­thing worth rec­og­niz­ing and tak­ing pride in.

The views ex­pressed by the au­thors of this blog are their own and do not nec­es­sar­ily re­flect the views of APNIC. Please note a Code of Conduct ap­plies to this blog.

Your brain was never designed for this much bad news

www.sciencedaily.com

During sev­eral re­cent con­ver­sa­tions, peo­ple have told me that they’ve stopped check­ing their phones in the morn­ing. Not be­cause noth­ing was hap­pen­ing, but be­cause every­thing was. They de­scribed the feel­ing as stand­ing un­der a wa­ter­fall of per­pet­ual bad news.

This ex­pe­ri­ence is far from an iso­lated one. According to Reuters Institute’s 2025 Digital News Report, 69 per­cent of Canadians at least oc­ca­sion­ally avoid the news now.

Globally, 40 per­cent re­port they at least some­times or of­ten do the same, the high­est fig­ure ever recorded. People shared con­sis­tent rea­sons for this: the news put them in a bad mood, they felt over­whelmed and pow­er­less to act.

As a re­searcher in de­vel­op­men­tal psy­chol­ogy, fo­cus­ing on so­cial de­vel­op­ment and psy­cho­log­i­cal well-be­ing, I ar­gue that news fa­tigue is not lazi­ness, weak­ness or a gen­er­a­tional de­cline in civic in­ter­est. It’s the pre­dictable re­sponse of a hu­man brain meet­ing an en­vi­ron­ment it was never de­signed to nav­i­gate.

Wired for bad news

Long be­fore smart­phones or even the print­ing press, our cog­ni­tive ar­chi­tec­ture was shaped by a sin­gle prob­lem: stay alive long enough to re­pro­duce. Our an­ces­tors whose at­ten­tion drifted past the rus­tle in the grass left fewer de­scen­dants than those who froze, looked and lis­tened.

The brain that paid at­ten­tion to threats was the brain that sur­vived.

This is the foun­da­tion of what psy­chol­o­gists call the neg­a­tiv­ity bias, one of the most repli­cated find­ings in cog­ni­tive sci­ence. Across decades of re­search, the hu­man mind has been shown to weigh neg­a­tive in­for­ma­tion more heav­ily than pos­i­tive, at­tend to it faster and re­mem­ber it longer.

A preda­tor nearby mat­tered more than a beau­ti­ful sun­set. The cost of miss­ing a real threat was death, while the cost of over­re­act­ing was a few min­utes of wasted vig­i­lance. The asym­me­try made this bias adap­tive.

Here is the prob­lem: the hu­man brain has not changed since then. We are the same species as we were thou­sands of years ago. What’s changed is the size of the world it’s asked to scan for threats.

Scanning the whole world

For most of hu­man his­tory, the threats our ner­vous sys­tem processed were lo­cal. A neigh­bour­ing tribe. A drought. The ill­ness of a child we per­son­ally knew. Information about dis­tant places would barely ar­rive, and if it did, it was mainly ir­rel­e­vant.

In 2026, the same neu­ro­log­i­cal sys­tem is be­ing asked to ab­sorb a war in one re­gion, a fi­nan­cial shock in an­other, a cli­mate dis­as­ter in a third and a vi­o­lent crime in a fourth, all be­fore lunchtime.

A study pub­lished in the sci­en­tific jour­nal Nature Human Behaviour ex­am­ined more than 105,000 real news head­lines viewed nearly six mil­lion times. Each ad­di­tional neg­a­tive word in­creased click-through rates, while pos­i­tive words had the op­po­site ef­fect.

Recent stud­ies sug­gest peo­ple around the world demon­strate mea­sur­ably stronger phys­i­o­log­i­cal re­sponses to neg­a­tive news than to pos­i­tive news. The body is re­act­ing be­fore the mind has de­cided whether the threat is rel­e­vant.

Some re­searchers have in­tro­duced a clin­i­cal frame­work for what hap­pens in this in­stance called Problematic News Consumption (PNC) — a pat­tern of news en­gage­ment that re­sults in pre­oc­cu­pa­tion, dys­reg­u­la­tion and dis­rup­tion to daily func­tion­ing. In their 2022 study, the re­searchers found that 17 per­cent of American adults qual­i­fied as hav­ing se­vere lev­els of PNC. Among that group, 61 per­cent re­ported feel­ing un­well quite a bit or very much, com­pared with six per­cent of those who did­n’t.

For mi­nor­ity pop­u­la­tions, news fa­tigue may be even more con­se­quen­tial.

Repeatedly wit­ness­ing harm di­rected at our own groups, even when we’re not the im­me­di­ate tar­get, can have a sig­nif­i­cant psy­cho­log­i­cal im­pact on peo­ple from the same group af­fil­i­a­tion. For racial­ized com­mu­ni­ties, such as im­mi­grants, the cog­ni­tive load could be even heav­ier, and the op­tion to sim­ply stop watch­ing is much harder to ex­er­cise when the news is about their coun­try of ori­gin.

Looking away is not the fix

What’s the so­lu­tion to news fa­tigue? Well, it’s not avoid­ance. A democ­racy de­pends on in­formed cit­i­zens.

Many adults al­ready cite the spread of mis­lead­ing in­for­ma­tion as a ma­jor source of stress. Withdrawing from ac­cu­rate, trust­wor­thy in­for­ma­tion only deep­ens the prob­lem. We’re wired to pay more at­ten­tion to bad news, and that kind of con­tent will find its way to us one way or an­other.

The fix is to man­age the con­sump­tion and the sources.

Several ap­proaches can help man­age news fa­tigue and pro­tect men­tal health. Containing news con­sump­tion to de­fined win­dows of time re­duces the sense of be­ing over­whelmed. Choosing depth over vol­ume also mat­ters: one care­fully re­ported long-form ar­ti­cle will in­form you bet­ter than bursts of ran­dom, un­re­li­able and emo­tion­ally loaded posts on Instagram.

There is also value in dis­tin­guish­ing be­tween in­for­ma­tion and ac­tion — re­search on per­ceived con­trol and stress con­sis­tently shows that the gap be­tween aware­ness and agency is one of the strongest pre­dic­tors of psy­cho­log­i­cal dis­tress. Identifying what you can ac­tu­ally do about what you read in the news, how­ever small, reg­u­lates that re­sponse.

Finally, be wary of rage bait” — in­ten­tion­ally provoca­tive mes­sages or con­tent de­signed to boost en­gage­ment on so­cial me­dia plat­forms by elic­it­ing neg­a­tive re­ac­tions. Recognizing that cer­tain con­tent cre­ators want to pro­voke rather than re­flect re­al­ity cre­ates use­ful cog­ni­tive dis­tance.

The news will not be­come less heavy.” But our re­la­tion­ship with it can be­come more de­lib­er­ate. Our brains were not built for this scale of in­put. They were, how­ever, built to learn to adapt.

Developers don't understand CORS

fosterelli.co

Developers don’t un­der­stand CORS

July 10, 2019 — Chris Foster

One of the best things about work­ing in full stack con­sult­ing is that I get to work with a great num­ber of de­vel­op­ers with dif­fer­ent skill lev­els in com­pa­nies from var­i­ous sizes and in­dus­tries. This pro­vides an op­por­tu­nity to see what uni­ver­sal strug­gles come up. One that seems com­mon and rel­e­vant re­cently is this: Too many web de­vel­op­ers do not un­der­stand how CORS works.

This seems par­tic­u­larly timely to point out be­cause of the re­cent Zoom vul­ner­a­bil­ity. Security re­searcher Jonathan Leitschuh found Zoom has a web server lis­ten­ing on the ma­chine at http://​lo­cal­host:19421. When you load a Zoom link, Zoom’s web­site sends a re­quest to the lo­cal­host web­server and tells it to open up the na­tive Zoom app. The whole ar­ti­cle is worth a read, but these parts stuck out to me:

I also found that, in­stead of mak­ing a reg­u­lar AJAX re­quest, this page in­stead loads an im­age from the Zoom web server that is lo­cally run­ning. The dif­fer­ent di­men­sions of the im­age dic­tate the er­ror/​sta­tus code of the server. You can see that case-switch logic here. One ques­tion I asked is, why is this web server re­turn­ing this data en­coded in the di­men­sions of an im­age file? The rea­son is, it’s done to by­pass Cross-Origin Resource Sharing (CORS). For very in­ten­tional rea­sons, the browser ex­plic­itly ig­nores any CORS pol­icy for servers run­ning on lo­cal­host.

I also found that, in­stead of mak­ing a reg­u­lar AJAX re­quest, this page in­stead loads an im­age from the Zoom web server that is lo­cally run­ning. The dif­fer­ent di­men­sions of the im­age dic­tate the er­ror/​sta­tus code of the server. You can see that case-switch logic here.

One ques­tion I asked is, why is this web server re­turn­ing this data en­coded in the di­men­sions of an im­age file? The rea­son is, it’s done to by­pass Cross-Origin Resource Sharing (CORS). For very in­ten­tional rea­sons, the browser ex­plic­itly ig­nores any CORS pol­icy for servers run­ning on lo­cal­host.

That last sen­tence is in­cor­rect — Chrome does re­spect CORS head­ers for lo­cal­host web­servers. If you’re a web de­vel­oper you’ve prob­a­bly done this when you have Create React App with your fron­tend app on one port and your back­end API on an­other port. Your app is mak­ing cross ori­gin re­quests against lo­cal­host, and this is sup­ported in all browsers.

What this says to me is that Zoom may have needed to get this fea­ture out and did not un­der­stand CORS. They could­n’t make the AJAX re­quests with­out the browser dis­al­low­ing the at­tempt. Instead, they built this im­age hack to work around CORS. By do­ing this, they opened Zoom up to a big vul­ner­a­bil­ity be­cause not only can the Zoom web­site trig­ger op­er­a­tions in the na­tive client and ac­cess the re­sponse, but every other web­site on the in­ter­net can too.

So what would a se­cure im­ple­men­ta­tion of this fea­ture look like? The web­server lis­ten­ing in on lo­cal­host:19421 should im­ple­ment a REST API and set a Access-Control-Allow-Origin header with the value https://​zoom.us. This will en­sure that only Javascript run­ning on the zoom.us do­main can talk to the lo­cal­host web­server. Further, to stop pages be­ing able to open Zoom meet­ings au­to­mat­i­cally in the back­ground zoom.us should have a Content Security Policy header that blocks ren­der­ing within an iframe.

This still leaves the vul­ner­a­bil­ity that any page can redi­rect your browser to a zoom.us link for a meet­ing that you did­n’t ex­pect, but this is a user ex­pe­ri­ence de­ci­sion that Zoom has made rather than a soft­ware vul­ner­a­bil­ity. Personally, I think the ap­proach is wrong here too. They men­tion they de­sired a bet­ter user ex­pe­ri­ence by open­ing the ap­pli­ca­tion di­rectly, but one of the rules of good user ex­pe­ri­ence de­sign is that your soft­ware must be pre­dictable.

If I am click­ing a link, I ex­pect that it will not sud­denly make my cam­era and mi­cro­phone avail­able to peo­ple I do not know. Zoom is break­ing this ex­pec­ta­tion. Even if they don’t want the built-in browser popup for UX rea­sons, put this popup in-app! Google Meet does this well:

I don’t want to take away from the CORS fo­cus of this post. Regardless of the user ex­pe­ri­ence side of the ar­gu­ment, run­ning a web­server on lo­cal­host is a risky en­deav­our to be­gin with. It should ab­solutely not be pro­vid­ing priv­i­leged ac­cess to func­tions, such as in­stalling soft­ware, to every web­site on the in­ter­net. CORS en­ables you to se­curely do this — don’t hack around it!

I can’t know for sure if fail­ure to un­der­stand CORS is why Zoom im­ple­mented the fea­ture this way. However, I’ve talked to a few peo­ple and none of us can col­lec­tively find any le­git­i­mate rea­son to im­ple­ment their ex­ist­ing ap­proach. On red­dit, leruni­corn did find and sug­gest that Firefox may block XHRs from se­cure to non-se­cure ori­gins which could ex­plain the mo­ti­va­tion be­hind this ap­proach. However, Firefox sup­ports this when the ori­gin is lo­cal­host. Further, na­tive apps can gen­er­ate a unique self-signed cer­tifi­cate. Alternatively, they could have used a browser ex­ten­sion. In any pos­si­ble case, this is not a valid rea­son to for­get to fil­ter ori­gins.

It’s not just Zoom. Anecdotally, lots of de­vel­op­ers I’ve talked with don’t un­der­stand well how CORS works. There’s also very a gen­er­ous quan­tity of ex­am­ples from ques­tions on Stack Overflow. Unfortunately, these are of­ten paired with pages that rec­om­mend very in­se­cure de­faults like this one in ex­press which would make your ap­pli­ca­tion vul­ner­a­ble if copied ver­ba­tim. Other ven­dors have been caught with the ex­act same vul­ner­a­bil­ity found in Zoom.

Developers just want to get their code to work, and by­pass­ing the same-ori­gin pol­icy en­tirely might get it to work, but when some­one finds out what you’ve done you’ll get prob­lems like Zoom has now.

I’ve seen CORS con­fu­sion from both ex­pe­ri­enced and new de­vel­op­ers. Is the CORS API too com­plex and con­fus­ing, or do we only need bet­ter de­vel­oper ed­u­ca­tion around is­sues like CORS and CSP? I’m not sure, but the cur­rent ap­proach def­i­nitely does­n’t seem like it’s work­ing.

epoll vs io_uring in Linux

sibexi.co

First, I want to tell you how ex­actly I got to this point and why I started re­search­ing dif­fer­ent op­tions for han­dling asyn­chro­nous I/O on Linux… Last year, my stu­dents and I built a re­verse proxy server called TinyGate. It was su­per sim­ple, worker-based, and it ba­si­cally worked well. Of course, I did­n’t ex­pect it to be very fast, but it was an ed­u­ca­tional pro­ject, and since we’d made a real, kind of pro­duc­tion-ready tool, I was re­ally proud of it. But my stu­dents weren’t as happy as I was - they wanted to build some­thing gen­uinely use­ful, and they were re­ally dis­ap­pointed that our product” had strong ar­chi­tec­tural lim­its and could­n’t out­per­form ti­tans like ng­inx and haproxy. So they lit­er­ally forced me to re­search to­gether how those tools work un­der the hood and how to han­dle asyn­chro­nous I/O to cut down on the heavy over­head… Long story short, we made a sec­ond ver­sion of TinyGate, based on epoll. It still lost to ng­inx/​haproxy in bench­marks, but it had a dra­matic per­for­mance boost com­pared to the first ver­sion. But epoll is­n’t per­fect ei­ther (as I’ll ex­plain be­low), and we even­tu­ally switched to io_ur­ing, which led to a full rewrite of our pro­ject from scratch, again… So it’s a re­ally in­ter­est­ing topic, and to­day I’ll share an overview of the two queue­ing sys­tems Linux gives you for asyn­chro­nous I/O.

epoll her­itage

When I just started de­vel­op­ing for Linux, epoll was a new fea­ture, and ba­si­cally it had no al­ter­na­tives. Everyone used it to man­age asyn­chro­nous ex­e­cu­tion - there was no other choice. The prob­lem is, epoll re­lies heav­ily on syscalls: it tells you when I/O is pos­si­ble, but you still have to call read()/​write() your­self af­ter­ward - that’s two syscalls per I/O event, on top of the one-time epol­l_ctl reg­is­tra­tion. Each of these syscalls causes a con­text switch be­tween user and ker­nel mode, which cre­ates HUGE over­head once you’re han­dling a lot of con­nec­tions. But we have a so­lu­tion! About 17 years af­ter epoll landed in the Linux ker­nel (2002), io_ur­ing ap­peared (2019)! Instead of telling you when I/O is pos­si­ble, it tells you when I/O is done - no polling loop, and far less as­so­ci­ated syscalls.

The ker­nel con­sumes sub­mis­sions from mem­ory shared be­tween your app and the ker­nel, and posts com­ple­tions back into that same shared mem­ory - both live in ring buffers, hence the name. The catch: by de­fault you still have to call io_ur­ing_en­ter() to tell the ker­nel go check the sub­mis­sion queue” - but one call can sub­mit a whole batch of op­er­a­tions and reap a whole batch of com­ple­tions, in­stead of one syscall pair per op­er­a­tion like with epoll + read. If you want close to zero syscalls dur­ing steady state, there’s IORING_SETUP_SQPOLL, which spins up a ded­i­cated ker­nel thread that polls the sub­mis­sion queue for you - at the cost of that thread burn­ing CPU (more on this be­low).

A lit­tle com­par­i­son

Basic ar­chi­tec­ture: as I said be­fore, epoll no­ti­fies you when I/O is pos­si­ble, io_ur­ing no­ti­fies you when I/O is done. Where epoll makes every I/O op­er­a­tion cross the ker­nel bound­ary, io_ur­ing lets you pay a small setup fee” once (creating the ring) plus a per-batch fee (the io_ur­ing_en­ter() call) in­stead of a fee per op­er­a­tion. So in­stead of a syscall pair per I/O, you get a syscall per batch of I/Os - or, with SQPOLL, close to none at all. As you can see, with a ton of I/O hap­pen­ing, this saves a lot of syscalls.

On rel­a­tively new sys­tems where io_ur­ing is sup­ported (kernel v5.1+, re­leased in 2019), there’s of­ten not much rea­son to reach for epoll. The shift from a readi­ness model to a com­ple­tion model is a huge ar­chi­tec­tural change - it moves a big part of the work out of your ap­pli­ca­tion and into the ker­nel.

Let’s code!

Of course, I won’t leave you with­out some code show­ing how both sys­tems work. We’ll use C. (The io_ur­ing ex­am­ple uses libur­ing, the user­space helper li­brary - in­stall it via libur­ing-dev/​libur­ing-de­vel, or drop down to the raw io_ur­ing_setup/​io_ur­ing_en­ter syscalls if you want zero de­pen­den­cies.)

epoll

Let’s make a sim­ple ex­am­ple of how epoll works. We’ll cre­ate the in­stance, reg­is­ter a file de­scrip­tor (stdin, in our case), and process the in­com­ing event.

As you can see, this ex­am­ple uses three syscalls in to­tal: epol­l_ctl (a one-time reg­is­tra­tion), then epol­l_wait and read for the event - so two syscalls per ac­tual I/O event, like I men­tioned above. The code it­self is pretty easy to fol­low.

io_ur­ing

Now let’s do the same thing with io_ur­ing in­stead of epoll.

What can we see here?

Similar in­stance cre­ation step.

No epol­l_ctl reg­is­tra­tion step needed.

No readi­ness check needed be­fore sub­mis­sion.

No sep­a­rate read() call at com­ple­tion.

Yeah, io_ur­ing takes way fewer re­sources for this - though, as noted above, there’s still one io_ur­ing_en­ter() call hid­ing in­side io_ur­ing_­sub­mit() and io_ur­ing_wait­_cqe() un­less you’re run­ning with SQPOLL.

When you test these ex­am­ples, keep in mind that for the sake of sim­plic­ity, some im­por­tant parts are miss­ing. For ex­am­ple, it will block for­ever if stdin never pro­duces any data, and the io_ur­ing ex­am­ple skips check­ing for a NULL sqe (which io_ur­ing_get_sqe() can re­turn if the sub­mis­sion queue is full).

Something ad­di­tional about io_ur­ing

Zero-copy. For real zero-copy I/O, reg­is­ter your buffers ahead of time with io_ur­ing_reg­is­ter_buffers() - this avoids the ker­nel re-map­ping mem­ory on every sin­gle op­er­a­tion. For net­work sends specif­i­cally, look at IORING_OP_SEND_ZC (kernel 6.0+ needed), which skips copy­ing the buffer into the ker­nel en­tirely.

SQPOLL uses CPU. Even when your queue is empty, IORING_SETUP_SQPOLL keeps a ker­nel thread spin­ning and polling, which burns CPU. There’s an idle time­out (sq_thread_idle) af­ter which it backs off to sleep­ing, but it’s not free.

Asynchronous er­ror han­dling. Errors come back (and must be han­dled) asyn­chro­nously, as part of the cqe’s res field - not as a di­rect re­turn value like a nor­mal syn­chro­nous syscall.

Summary

io_ur­ing is the new stan­dard for async I/O in the mod­ern Linux world, and hon­estly, I don’t see much rea­son to still reach for epoll on a sys­tem that has it. For a from-scratch pro­ject on a mod­ern Linux server, like our TinyGate rewrite, io_ur­ing is ab­solutely the way to go. I’m a die-hard sup­porter of drop­ping sup­port for old sys­tems as soon as it’s rea­son­able - if you’re still run­ning a ker­nel re­leased more than 7 years ago, in my opin­ion, that’s not a great idea…

TownSquare, a tiny presence layer for websites

townsquare.cauenapier.com

Your web­site, but in­hab­ited.

The web is full of con­tent but empty of peo­ple. TownSquare brings a lit­tle pres­ence back. Visitors can see each other, say a few words, and share the same space. No ac­counts. No al­go­rithms. Just the pre­sent.

Live demo

Step into a shared square

Tap Activate demo to step in.

Click, tap, or use ← → to move · Press T or tap your name to say some­thing · Press J to jump and H to high-five with some­one

Three small steps

One snip­pet, and your page feels alive

1

Paste one snip­pet

Drop a sin­gle <script> tag be­fore </body>. No build step, no de­pen­den­cies.

2

Visitors ap­pear

Visitors can see each other the mo­ment they ar­rive.

3

They share the mo­ment

Move around, in­ter­act with the en­vi­ron­ment, say hello, and share the mo­ment.

What peo­ple are say­ing

Little mo­ments, shared in real time

I haven’t en­coun­tered some­thing this fun and play­ful on the web in so long”

Yeah, I don’t know why but I al­ways start smil­ing see­ing peo­ple chat­ting this way”

Thank you for mak­ing my cof­fee break in­ter­est­ing”

A grow­ing world of pub­lic squares

— reg­is­tered TownSquares

— on the map

— mes­sages ex­changed

— GitHub stars

Connect your site and be­come part of a grow­ing net­work of in­hab­ited cor­ners of the web.

Join a grow­ing net­work of in­hab­ited cor­ners of the web.

Lyme disease tick test: Home test kit seeks to limit spread

www.bostonglobe.com

But soon you’ll be able to run a 15-minute tick test in your liv­ing room. It’s called LymeAlert, and it’s due to go on sale in August, priced at $40 per test.

Company founder Erin Dawicki, a pe­di­atric or­tho­pe­dic physi­cian as­sis­tant, came up with the con­cept while work­ing to­ward an MBA from the Sloan School of Management at the Massachusetts Institute of Technology.

I went to MIT be­cause I was get­ting so an­gry at the US health­care sys­tem,” Dawicki said, because it forces me to treat peo­ple dif­fer­ently based on their in­sur­ance sta­tus and that’s their so­cioe­co­nomic sta­tus. And frankly, that goes against my eth­i­cal frame­work.”

She fig­ured that an MIT de­gree would help her find tech­no­log­i­cal so­lu­tions to even out health care dis­par­i­ties. I thought I was go­ing to work on health care re­form at the fed­eral level,” Dawicki said. Clearly, the uni­verse had other plans.

Instead, she was dragged kick­ing and scream­ing” into a course on health care en­tre­pre­neur­ship. Arriving two weeks af­ter the course had be­gun, she was as­signed to come up with a prod­uct to im­prove the treat­ment of Lyme dis­ease. But she was­n’t sure how to pro­ceed.

Dawicki’s break­through came to her in the shower. I get phone calls all the time from my pa­tients,” she thought. Hey, I found a tick on me. What do I do?”

Usually, Dawicki told them to come in and get a dose of an anti-Lyme an­tibi­otic, just in case. But while over half of ticks in Massachusetts carry Lyme dis­ease, nearly half do not. An un­nec­es­sary doc­tor visit costs money, and un­nec­es­sary doses of an­tibi­otics in­crease the risk that dis­eases will be­come more re­sis­tant to the drug.

Why not test the tick first? Just like that, Dawicki had her class pro­ject. When she sug­gested it in class, four fel­low stu­dents of­fered to pitch in. So did Dawicki’s hus­band, a me­chan­i­cal en­gi­neer.

The re­sult is LymeAlert. The test is pain­less for hu­mans, but hard on ticks. It comes with a plas­tic con­tainer and a built-in grinder. A user drops up to five ticks into the con­tainer, then closes and twists it, grind­ing the ticks into pulp. Next, the user in­serts a piece of chem­i­cally treated pa­per, which changes color if Lyme dis­ease bac­te­ria are pre­sent.

For the peo­ple who find a tick, and it’s pos­i­tive, we can give them one dose of an­tibi­otic and have a pretty good chance of pre­vent­ing the dis­ease,” Dawicki said.

It’s good news if it works, said Armin Alaedini, chief sci­en­tific of­fi­cer of the Global Lyme Alliance, a non­profit seek­ing cures for the dis­ease. A quick, sim­ple Lyme test could give bite vic­tims a head start on get­ting an­tibi­otics. But if it’s not a good test and it gives false pos­i­tives, it can be mis­lead­ing and it could cause panic,” Alaedini said.

In ad­di­tion, he noted that the test won’t re­veal whether the tick is car­ry­ing other in­fec­tious agents, such as the tick-borne sub­stance that causes Alpha-gal syn­drome. The best thing is to go see a doc­tor when you get that tick bite,” Alaedini said.

Dawicki con­cedes that LymeAlert can’t test for every pos­si­ble haz­ard. She said the com­pany is work­ing on a fu­ture ver­sion ca­pa­ble of de­tect­ing other pathogens, and hopes to bring it to mar­ket next year.

In the mean­time, she said, it’s es­pe­cially im­por­tant to get a head start on treat­ing Lyme dis­ease be­cause it’s the only ma­jor tick-borne in­fec­tion that can be treated with an an­tibi­otic be­fore it be­comes se­ri­ous. Besides, in­fec­tious dis­ease ex­perts say that the an­tibi­otic should be ad­min­is­tered within 72 hours of de­tect­ing the tick.

Helping in­fected peo­ple is just the be­gin­ning. LymeAlert will also of­fer a smart­phone app that en­ables users to anony­mously re­port the lo­ca­tions where in­fected ticks are found.

We’re re­fin­ing those ticks down to the neigh­bor­hood level,” Dawicki said, and then we’re over­lay­ing that with NASA satel­lite data and mi­gra­tory an­i­mal data to do an AI pre­dic­tive al­go­rithm of where dif­fer­ent tick species and dif­fer­ent pathogens are likely to spread.”

In short, she’s putting ticks un­der sur­veil­lance in hopes of leav­ing Lyme dis­ease with nowhere to hide.

✈️ A flight in one of the world’s first elec­tric air­planes. Read more from tech re­porter Aaron Pressman.

🗞️ A South Shore AI-generated news site put up a pay­wall. Hundreds of read­ers, in­clud­ing a po­lice chief, opened their wal­lets. Read more from me­dia re­porter Aidan Ryan.

🦾 A ro­botic hand talks’ to deaf and blind peo­ple. Here’s how it works. Read more from tech colum­nist Hiawatha Bray.

💰 Mo Alkhadra draws up to $20 mil­lion in fed­eral funds to his startup, Lithios. Read more from busi­ness re­porter Jon Chesto.

🎓 New grad­u­a­tion re­quire­ments rec­om­mended for Mass. high school­ers in­clude tests, AI train­ing, and fi­nan­cial lit­er­acy. Read more from ed­u­ca­tion re­porter Marcela Rodrigues.

🏝️ Travel site Tripadvisor in Needham is sell­ing TheFork, its European restau­rant reser­va­tion unit, to American Express for $700 mil­lion. The deal is ex­pected to close be­fore the end of 2026.

🤑 Metals tech com­pany Foundation Alloy in Boston raised $22 mil­lion in a deal led by Voyager Ventures and in­clud­ing America’s Frontier Fund, Overlap Holdings, Material Impact, Engine Ventures, and El Cap.

🏛️ Legal AI soft­ware firm Summize in Boston ac­quired the per­son­nel and as­sets of InnoLaw Group. InnoLaw CEO and founder Lucy Bassli will not join Summize. Terms of the deal were not dis­closed.

🤝 IT ser­vices com­pany Stonewall Solutions in Marlborough was ac­quired by xFact. Terms of the deal were not dis­closed.

👋 Private eq­uity firm Great Hill Partners in Boston hired Lauren Reddy as head of peo­ple. Reddy pre­vi­ously was chief tal­ent of­fi­cer at L.E.K. Consulting.

🚀 Elon Musk’s SpaceX went pub­lic and started trad­ing on the Nasdaq with a stock mar­ket value ex­ceed­ing $2 tril­lion, mak­ing Musk the world’s first tril­lion­aire (at least on pa­per).

What We’re Reading

MrBeast Hits 500 Million Subscribers on YouTube (The Wrap)

Why Orbital Data Centers Are Harder Than Silicon Valley Thinks (IEEE Spectrum)

The Hacker Sent by Anthropic to Calm the Government’s Nerves About AI Safety (Wall Street Journal)

👋 Thanks for read­ing. We’ll be will be back next Wednesday.

❓ Have a tip? Email Hiawatha at hi­awatha.bray@globe.com.

✍🏼 If some­one sent you this newslet­ter, you can sign up for your own copy.

Hiawatha Bray can be reached at hi­awatha.bray@globe.com. Follow him @GlobeTechLab.

To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".

10HN is also available as an iOS App

If you visit 10HN only rarely, check out the the best articles from the past week.

Visit pancik.com for more.